[llvm-branch-commits] [mlir] 2217cac - [mlir][py] better support for arith.constant construction
Author: Alex Zinenko Date: 2024-02-28T12:53:53Z New Revision: 2217caceac600f5c0e84a0d6a55ec036e13ebf6a URL: https://github.com/llvm/llvm-project/commit/2217caceac600f5c0e84a0d6a55ec036e13ebf6a DIFF: https://github.com/llvm/llvm-project/commit/2217caceac600f5c0e84a0d6a55ec036e13ebf6a.diff LOG: [mlir][py] better support for arith.constant construction Arithmetic constants for vector types can be constructed from objects implementing Python buffer protocol such as `array.array`. Note that until Python 3.12, there is no typing support for buffer protocol implementers, so the annotations use array explicitly. Added: Modified: mlir/python/mlir/dialects/arith.py mlir/test/python/dialects/arith_dialect.py Removed: diff --git a/mlir/python/mlir/dialects/arith.py b/mlir/python/mlir/dialects/arith.py index 61c6917393f1f9..83a50c7ef244f1 100644 --- a/mlir/python/mlir/dialects/arith.py +++ b/mlir/python/mlir/dialects/arith.py @@ -5,6 +5,8 @@ from ._arith_ops_gen import * from ._arith_ops_gen import _Dialect from ._arith_enum_gen import * +from array import array as _array +from typing import overload try: from ..ir import * @@ -43,13 +45,30 @@ def _is_float_type(type: Type): class ConstantOp(ConstantOp): """Specialization for the constant op class.""" +@overload +def __init__(self, value: Attribute, *, loc=None, ip=None): +... + +@overload def __init__( -self, result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +self, result: Type, value: Union[int, float, _array], *, loc=None, ip=None ): +... + +def __init__(self, result, value, *, loc=None, ip=None): +if value is None: +assert isinstance(result, Attribute) +super().__init__(result, loc=loc, ip=ip) +return + if isinstance(value, int): super().__init__(IntegerAttr.get(result, value), loc=loc, ip=ip) elif isinstance(value, float): super().__init__(FloatAttr.get(result, value), loc=loc, ip=ip) +elif isinstance(value, _array) and value.typecode in ["i", "l"]: +super().__init__(DenseIntElementsAttr.get(value, type=result)) +elif isinstance(value, _array) and value.typecode in ["f", "d"]: +super().__init__(DenseFPElementsAttr.get(value, type=result)) else: super().__init__(value, loc=loc, ip=ip) @@ -79,6 +98,6 @@ def literal_value(self) -> Union[int, float]: def constant( -result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +result: Type, value: Union[int, float, Attribute, _array], *, loc=None, ip=None ) -> Value: return _get_op_result_or_op_results(ConstantOp(result, value, loc=loc, ip=ip)) diff --git a/mlir/test/python/dialects/arith_dialect.py b/mlir/test/python/dialects/arith_dialect.py index 8bb80eed2b8105..ef0e1620bba990 100644 --- a/mlir/test/python/dialects/arith_dialect.py +++ b/mlir/test/python/dialects/arith_dialect.py @@ -4,6 +4,7 @@ from mlir.ir import * import mlir.dialects.arith as arith import mlir.dialects.func as func +from array import array def run(f): @@ -92,3 +93,40 @@ def __str__(self): b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) + + +# CHECK-LABEL: TEST: testArrayConstantConstruction +@run +def testArrayConstantConstruction(): +with Context(), Location.unknown(): +module = Module.create() +with InsertionPoint(module.body): +i32_array = array("i", [1, 2, 3, 4]) +i32 = IntegerType.get_signless(32) +vec_i32 = VectorType.get([2, 2], i32) +arith.constant(vec_i32, i32_array) +arith.ConstantOp(vec_i32, DenseIntElementsAttr.get(i32_array, type=vec_i32)) + +i64_array = array("l", [5, 6, 7, 8]) +i64 = IntegerType.get_signless(64) +vec_i64 = VectorType.get([1, 4], i64) +arith.constant(vec_i64, i64_array) +arith.ConstantOp(vec_i64, DenseIntElementsAttr.get(i64_array, type=vec_i64)) + +f32_array = array("f", [1.0, 2.0, 3.0, 4.0]) +f32 = F32Type.get() +vec_f32 = VectorType.get([4, 1], f32) +arith.constant(vec_f32, f32_array) +arith.ConstantOp(vec_f32, DenseFPElementsAttr.get(f32_array, type=vec_f32)) + +f64_array = array("d", [1.0, 2.0, 3.0, 4.0]) +f64 = F64Type.get() +vec_f64 = VectorType.get([2, 1, 2], f64) +arith.constant(vec_f64, f64_array) +arith.ConstantOp(vec_f64, DenseFPElementsAttr.get(f64_array, type=vec_f64)) + +# CHECK-COUNT-2: arith.constant dense<[{{\[}}1, 2], [3, 4]]> : vector<2x2xi32> +# CHECK-COUNT-2: arith.constant dense<[{{\[}}5, 6, 7, 8]]> : vector<1x4xi64> +# CHECK-COUNT-2: ari
[llvm-branch-commits] [mlir] 1ccfb41 - printf debugging
Author: Alex Zinenko Date: 2024-03-06T10:49:17Z New Revision: 1ccfb41ab32ac27b32919438a11806bd688a030d URL: https://github.com/llvm/llvm-project/commit/1ccfb41ab32ac27b32919438a11806bd688a030d DIFF: https://github.com/llvm/llvm-project/commit/1ccfb41ab32ac27b32919438a11806bd688a030d.diff LOG: printf debugging Added: Modified: mlir/lib/IR/BuiltinAttributes.cpp Removed: diff --git a/mlir/lib/IR/BuiltinAttributes.cpp b/mlir/lib/IR/BuiltinAttributes.cpp index 89b1ed67f5d067..2f3798ed54f2f3 100644 --- a/mlir/lib/IR/BuiltinAttributes.cpp +++ b/mlir/lib/IR/BuiltinAttributes.cpp @@ -1084,6 +1084,11 @@ bool DenseElementsAttr::isValidRawBuffer(ShapedType type, return rawBufferWidth == llvm::alignTo<8>(numElements); } + llvm::errs() << "storage width: " << storageWidth + << " rawBufferWidth: " << rawBufferWidth + << " numElements: " << numElements << "\n"; + type.dump(); + // All other types are 8-bit aligned, so we can just check the buffer width // to know if only a single initializer element was passed in. if (rawBufferWidth == storageWidth) { ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 0c81122 - [mlir][py] better support for arith.constant construction
Author: Alex Zinenko Date: 2024-03-06T18:30:09Z New Revision: 0c81122420979a28d16beddaed85413fd533c324 URL: https://github.com/llvm/llvm-project/commit/0c81122420979a28d16beddaed85413fd533c324 DIFF: https://github.com/llvm/llvm-project/commit/0c81122420979a28d16beddaed85413fd533c324.diff LOG: [mlir][py] better support for arith.constant construction Arithmetic constants for vector types can be constructed from objects implementing Python buffer protocol such as `array.array`. Note that until Python 3.12, there is no typing support for buffer protocol implementers, so the annotations use array explicitly. Added: Modified: mlir/python/mlir/dialects/arith.py mlir/test/python/dialects/arith_dialect.py Removed: diff --git a/mlir/python/mlir/dialects/arith.py b/mlir/python/mlir/dialects/arith.py index 61c6917393f1f9..92da5df9bce665 100644 --- a/mlir/python/mlir/dialects/arith.py +++ b/mlir/python/mlir/dialects/arith.py @@ -5,6 +5,8 @@ from ._arith_ops_gen import * from ._arith_ops_gen import _Dialect from ._arith_enum_gen import * +from array import array as _array +from typing import overload try: from ..ir import * @@ -43,13 +45,37 @@ def _is_float_type(type: Type): class ConstantOp(ConstantOp): """Specialization for the constant op class.""" +@overload +def __init__(self, value: Attribute, *, loc=None, ip=None): +... + +@overload def __init__( -self, result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +self, result: Type, value: Union[int, float, _array], *, loc=None, ip=None ): +... + +def __init__(self, result, value, *, loc=None, ip=None): +if value is None: +assert isinstance(result, Attribute) +super().__init__(result, loc=loc, ip=ip) +return + if isinstance(value, int): super().__init__(IntegerAttr.get(result, value), loc=loc, ip=ip) elif isinstance(value, float): super().__init__(FloatAttr.get(result, value), loc=loc, ip=ip) +elif isinstance(value, _array): +if 8 * value.itemsize != result.element_type.width: +raise ValueError( +f"Mismatching array element ({8 * value.itemsize}) and type ({result.element_type.width}) width." +) +if value.typecode in ["i", "l", "q"]: +super().__init__(DenseIntElementsAttr.get(value, type=result)) +elif value.typecode in ["f", "d"]: +super().__init__(DenseFPElementsAttr.get(value, type=result)) +else: +raise ValueError(f'Unsupported typecode: "{value.typecode}".') else: super().__init__(value, loc=loc, ip=ip) @@ -79,6 +105,6 @@ def literal_value(self) -> Union[int, float]: def constant( -result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +result: Type, value: Union[int, float, Attribute, _array], *, loc=None, ip=None ) -> Value: return _get_op_result_or_op_results(ConstantOp(result, value, loc=loc, ip=ip)) diff --git a/mlir/test/python/dialects/arith_dialect.py b/mlir/test/python/dialects/arith_dialect.py index 8bb80eed2b8105..c9af5e7b46db84 100644 --- a/mlir/test/python/dialects/arith_dialect.py +++ b/mlir/test/python/dialects/arith_dialect.py @@ -4,6 +4,7 @@ from mlir.ir import * import mlir.dialects.arith as arith import mlir.dialects.func as func +from array import array def run(f): @@ -92,3 +93,42 @@ def __str__(self): b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) + + +# CHECK-LABEL: TEST: testArrayConstantConstruction +@run +def testArrayConstantConstruction(): +with Context(), Location.unknown(): +module = Module.create() +with InsertionPoint(module.body): +i32_array = array("i", [1, 2, 3, 4]) +i32 = IntegerType.get_signless(32) +vec_i32 = VectorType.get([2, 2], i32) +arith.constant(vec_i32, i32_array) +arith.ConstantOp(vec_i32, DenseIntElementsAttr.get(i32_array, type=vec_i32)) + +# "q" is the equivalent of `long long` in C and requires at least +# 64 bit width integers on both Linux and Windows. +i64_array = array("q", [5, 6, 7, 8]) +i64 = IntegerType.get_signless(64) +vec_i64 = VectorType.get([1, 4], i64) +arith.constant(vec_i64, i64_array) +arith.ConstantOp(vec_i64, DenseIntElementsAttr.get(i64_array, type=vec_i64)) + +f32_array = array("f", [1.0, 2.0, 3.0, 4.0]) +f32 = F32Type.get() +vec_f32 = VectorType.get([4, 1], f32) +arith.constant(vec_f32, f32_array) +arith.ConstantOp(vec_f32, DenseFPElementsAttr.get(f32_array, type=vec_f32)) + +
[llvm-branch-commits] [flang] 7f10219 - [flang] disable failing test
Author: Alex Zinenko Date: 2024-03-07T10:36:58Z New Revision: 7f102199b862fce58e4b0d94d10f4cf14acb48e1 URL: https://github.com/llvm/llvm-project/commit/7f102199b862fce58e4b0d94d10f4cf14acb48e1 DIFF: https://github.com/llvm/llvm-project/commit/7f102199b862fce58e4b0d94d10f4cf14acb48e1.diff LOG: [flang] disable failing test This test has been failing on Windows for multiple consecutive days without any action taken. This prevents our CI from finding other problematic tests. Added: Modified: flang/test/Fir/memory-allocation-opt.fir Removed: diff --git a/flang/test/Fir/memory-allocation-opt.fir b/flang/test/Fir/memory-allocation-opt.fir index cfbca2f83ef8ec..c89d794ccaf8d0 100644 --- a/flang/test/Fir/memory-allocation-opt.fir +++ b/flang/test/Fir/memory-allocation-opt.fir @@ -1,4 +1,5 @@ // RUN: fir-opt --memory-allocation-opt="dynamic-array-on-heap=true maximum-array-alloc-size=1024" %s | FileCheck %s +// XFAIL: * // Test for size of array being too big. ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 20815bc - [mlir][py] better support for arith.constant construction
Author: Alex Zinenko Date: 2024-03-07T10:38:26Z New Revision: 20815bc3273ad1d63494ba3f6eda8a9671a94693 URL: https://github.com/llvm/llvm-project/commit/20815bc3273ad1d63494ba3f6eda8a9671a94693 DIFF: https://github.com/llvm/llvm-project/commit/20815bc3273ad1d63494ba3f6eda8a9671a94693.diff LOG: [mlir][py] better support for arith.constant construction Arithmetic constants for vector types can be constructed from objects implementing Python buffer protocol such as `array.array`. Note that until Python 3.12, there is no typing support for buffer protocol implementers, so the annotations use array explicitly. Added: Modified: mlir/python/mlir/dialects/arith.py mlir/test/python/dialects/arith_dialect.py Removed: diff --git a/mlir/python/mlir/dialects/arith.py b/mlir/python/mlir/dialects/arith.py index 61c6917393f1f9..92da5df9bce665 100644 --- a/mlir/python/mlir/dialects/arith.py +++ b/mlir/python/mlir/dialects/arith.py @@ -5,6 +5,8 @@ from ._arith_ops_gen import * from ._arith_ops_gen import _Dialect from ._arith_enum_gen import * +from array import array as _array +from typing import overload try: from ..ir import * @@ -43,13 +45,37 @@ def _is_float_type(type: Type): class ConstantOp(ConstantOp): """Specialization for the constant op class.""" +@overload +def __init__(self, value: Attribute, *, loc=None, ip=None): +... + +@overload def __init__( -self, result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +self, result: Type, value: Union[int, float, _array], *, loc=None, ip=None ): +... + +def __init__(self, result, value, *, loc=None, ip=None): +if value is None: +assert isinstance(result, Attribute) +super().__init__(result, loc=loc, ip=ip) +return + if isinstance(value, int): super().__init__(IntegerAttr.get(result, value), loc=loc, ip=ip) elif isinstance(value, float): super().__init__(FloatAttr.get(result, value), loc=loc, ip=ip) +elif isinstance(value, _array): +if 8 * value.itemsize != result.element_type.width: +raise ValueError( +f"Mismatching array element ({8 * value.itemsize}) and type ({result.element_type.width}) width." +) +if value.typecode in ["i", "l", "q"]: +super().__init__(DenseIntElementsAttr.get(value, type=result)) +elif value.typecode in ["f", "d"]: +super().__init__(DenseFPElementsAttr.get(value, type=result)) +else: +raise ValueError(f'Unsupported typecode: "{value.typecode}".') else: super().__init__(value, loc=loc, ip=ip) @@ -79,6 +105,6 @@ def literal_value(self) -> Union[int, float]: def constant( -result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +result: Type, value: Union[int, float, Attribute, _array], *, loc=None, ip=None ) -> Value: return _get_op_result_or_op_results(ConstantOp(result, value, loc=loc, ip=ip)) diff --git a/mlir/test/python/dialects/arith_dialect.py b/mlir/test/python/dialects/arith_dialect.py index 8bb80eed2b8105..c9af5e7b46db84 100644 --- a/mlir/test/python/dialects/arith_dialect.py +++ b/mlir/test/python/dialects/arith_dialect.py @@ -4,6 +4,7 @@ from mlir.ir import * import mlir.dialects.arith as arith import mlir.dialects.func as func +from array import array def run(f): @@ -92,3 +93,42 @@ def __str__(self): b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) + + +# CHECK-LABEL: TEST: testArrayConstantConstruction +@run +def testArrayConstantConstruction(): +with Context(), Location.unknown(): +module = Module.create() +with InsertionPoint(module.body): +i32_array = array("i", [1, 2, 3, 4]) +i32 = IntegerType.get_signless(32) +vec_i32 = VectorType.get([2, 2], i32) +arith.constant(vec_i32, i32_array) +arith.ConstantOp(vec_i32, DenseIntElementsAttr.get(i32_array, type=vec_i32)) + +# "q" is the equivalent of `long long` in C and requires at least +# 64 bit width integers on both Linux and Windows. +i64_array = array("q", [5, 6, 7, 8]) +i64 = IntegerType.get_signless(64) +vec_i64 = VectorType.get([1, 4], i64) +arith.constant(vec_i64, i64_array) +arith.ConstantOp(vec_i64, DenseIntElementsAttr.get(i64_array, type=vec_i64)) + +f32_array = array("f", [1.0, 2.0, 3.0, 4.0]) +f32 = F32Type.get() +vec_f32 = VectorType.get([4, 1], f32) +arith.constant(vec_f32, f32_array) +arith.ConstantOp(vec_f32, DenseFPElementsAttr.get(f32_array, type=vec_f32)) + +
[llvm-branch-commits] [mlir] b246e0d - [mlir][py] better support for arith.constant construction
Author: Alex Zinenko Date: 2024-03-07T10:44:36Z New Revision: b246e0d0bea735652274000fb73a7b2e46434612 URL: https://github.com/llvm/llvm-project/commit/b246e0d0bea735652274000fb73a7b2e46434612 DIFF: https://github.com/llvm/llvm-project/commit/b246e0d0bea735652274000fb73a7b2e46434612.diff LOG: [mlir][py] better support for arith.constant construction Arithmetic constants for vector types can be constructed from objects implementing Python buffer protocol such as `array.array`. Note that until Python 3.12, there is no typing support for buffer protocol implementers, so the annotations use array explicitly. Added: Modified: mlir/python/mlir/dialects/arith.py mlir/test/python/dialects/arith_dialect.py Removed: diff --git a/mlir/python/mlir/dialects/arith.py b/mlir/python/mlir/dialects/arith.py index 61c6917393f1f9..92da5df9bce665 100644 --- a/mlir/python/mlir/dialects/arith.py +++ b/mlir/python/mlir/dialects/arith.py @@ -5,6 +5,8 @@ from ._arith_ops_gen import * from ._arith_ops_gen import _Dialect from ._arith_enum_gen import * +from array import array as _array +from typing import overload try: from ..ir import * @@ -43,13 +45,37 @@ def _is_float_type(type: Type): class ConstantOp(ConstantOp): """Specialization for the constant op class.""" +@overload +def __init__(self, value: Attribute, *, loc=None, ip=None): +... + +@overload def __init__( -self, result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +self, result: Type, value: Union[int, float, _array], *, loc=None, ip=None ): +... + +def __init__(self, result, value, *, loc=None, ip=None): +if value is None: +assert isinstance(result, Attribute) +super().__init__(result, loc=loc, ip=ip) +return + if isinstance(value, int): super().__init__(IntegerAttr.get(result, value), loc=loc, ip=ip) elif isinstance(value, float): super().__init__(FloatAttr.get(result, value), loc=loc, ip=ip) +elif isinstance(value, _array): +if 8 * value.itemsize != result.element_type.width: +raise ValueError( +f"Mismatching array element ({8 * value.itemsize}) and type ({result.element_type.width}) width." +) +if value.typecode in ["i", "l", "q"]: +super().__init__(DenseIntElementsAttr.get(value, type=result)) +elif value.typecode in ["f", "d"]: +super().__init__(DenseFPElementsAttr.get(value, type=result)) +else: +raise ValueError(f'Unsupported typecode: "{value.typecode}".') else: super().__init__(value, loc=loc, ip=ip) @@ -79,6 +105,6 @@ def literal_value(self) -> Union[int, float]: def constant( -result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +result: Type, value: Union[int, float, Attribute, _array], *, loc=None, ip=None ) -> Value: return _get_op_result_or_op_results(ConstantOp(result, value, loc=loc, ip=ip)) diff --git a/mlir/test/python/dialects/arith_dialect.py b/mlir/test/python/dialects/arith_dialect.py index 8bb80eed2b8105..c9af5e7b46db84 100644 --- a/mlir/test/python/dialects/arith_dialect.py +++ b/mlir/test/python/dialects/arith_dialect.py @@ -4,6 +4,7 @@ from mlir.ir import * import mlir.dialects.arith as arith import mlir.dialects.func as func +from array import array def run(f): @@ -92,3 +93,42 @@ def __str__(self): b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) + + +# CHECK-LABEL: TEST: testArrayConstantConstruction +@run +def testArrayConstantConstruction(): +with Context(), Location.unknown(): +module = Module.create() +with InsertionPoint(module.body): +i32_array = array("i", [1, 2, 3, 4]) +i32 = IntegerType.get_signless(32) +vec_i32 = VectorType.get([2, 2], i32) +arith.constant(vec_i32, i32_array) +arith.ConstantOp(vec_i32, DenseIntElementsAttr.get(i32_array, type=vec_i32)) + +# "q" is the equivalent of `long long` in C and requires at least +# 64 bit width integers on both Linux and Windows. +i64_array = array("q", [5, 6, 7, 8]) +i64 = IntegerType.get_signless(64) +vec_i64 = VectorType.get([1, 4], i64) +arith.constant(vec_i64, i64_array) +arith.ConstantOp(vec_i64, DenseIntElementsAttr.get(i64_array, type=vec_i64)) + +f32_array = array("f", [1.0, 2.0, 3.0, 4.0]) +f32 = F32Type.get() +vec_f32 = VectorType.get([4, 1], f32) +arith.constant(vec_f32, f32_array) +arith.ConstantOp(vec_f32, DenseFPElementsAttr.get(f32_array, type=vec_f32)) + +
[llvm-branch-commits] [mlir] d39cb79 - [mlir][py] better support for arith.constant construction
Author: Alex Zinenko Date: 2024-03-07T15:02:35Z New Revision: d39cb79cddadbb6dc6914a8c9f0a54e0f8ce1329 URL: https://github.com/llvm/llvm-project/commit/d39cb79cddadbb6dc6914a8c9f0a54e0f8ce1329 DIFF: https://github.com/llvm/llvm-project/commit/d39cb79cddadbb6dc6914a8c9f0a54e0f8ce1329.diff LOG: [mlir][py] better support for arith.constant construction Arithmetic constants for vector types can be constructed from objects implementing Python buffer protocol such as `array.array`. Note that until Python 3.12, there is no typing support for buffer protocol implementers, so the annotations use array explicitly. Added: Modified: mlir/python/mlir/dialects/arith.py mlir/test/python/dialects/arith_dialect.py Removed: diff --git a/mlir/python/mlir/dialects/arith.py b/mlir/python/mlir/dialects/arith.py index 61c6917393f1f9..92da5df9bce665 100644 --- a/mlir/python/mlir/dialects/arith.py +++ b/mlir/python/mlir/dialects/arith.py @@ -5,6 +5,8 @@ from ._arith_ops_gen import * from ._arith_ops_gen import _Dialect from ._arith_enum_gen import * +from array import array as _array +from typing import overload try: from ..ir import * @@ -43,13 +45,37 @@ def _is_float_type(type: Type): class ConstantOp(ConstantOp): """Specialization for the constant op class.""" +@overload +def __init__(self, value: Attribute, *, loc=None, ip=None): +... + +@overload def __init__( -self, result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +self, result: Type, value: Union[int, float, _array], *, loc=None, ip=None ): +... + +def __init__(self, result, value, *, loc=None, ip=None): +if value is None: +assert isinstance(result, Attribute) +super().__init__(result, loc=loc, ip=ip) +return + if isinstance(value, int): super().__init__(IntegerAttr.get(result, value), loc=loc, ip=ip) elif isinstance(value, float): super().__init__(FloatAttr.get(result, value), loc=loc, ip=ip) +elif isinstance(value, _array): +if 8 * value.itemsize != result.element_type.width: +raise ValueError( +f"Mismatching array element ({8 * value.itemsize}) and type ({result.element_type.width}) width." +) +if value.typecode in ["i", "l", "q"]: +super().__init__(DenseIntElementsAttr.get(value, type=result)) +elif value.typecode in ["f", "d"]: +super().__init__(DenseFPElementsAttr.get(value, type=result)) +else: +raise ValueError(f'Unsupported typecode: "{value.typecode}".') else: super().__init__(value, loc=loc, ip=ip) @@ -79,6 +105,6 @@ def literal_value(self) -> Union[int, float]: def constant( -result: Type, value: Union[int, float, Attribute], *, loc=None, ip=None +result: Type, value: Union[int, float, Attribute, _array], *, loc=None, ip=None ) -> Value: return _get_op_result_or_op_results(ConstantOp(result, value, loc=loc, ip=ip)) diff --git a/mlir/test/python/dialects/arith_dialect.py b/mlir/test/python/dialects/arith_dialect.py index 8bb80eed2b8105..c9af5e7b46db84 100644 --- a/mlir/test/python/dialects/arith_dialect.py +++ b/mlir/test/python/dialects/arith_dialect.py @@ -4,6 +4,7 @@ from mlir.ir import * import mlir.dialects.arith as arith import mlir.dialects.func as func +from array import array def run(f): @@ -92,3 +93,42 @@ def __str__(self): b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) + + +# CHECK-LABEL: TEST: testArrayConstantConstruction +@run +def testArrayConstantConstruction(): +with Context(), Location.unknown(): +module = Module.create() +with InsertionPoint(module.body): +i32_array = array("i", [1, 2, 3, 4]) +i32 = IntegerType.get_signless(32) +vec_i32 = VectorType.get([2, 2], i32) +arith.constant(vec_i32, i32_array) +arith.ConstantOp(vec_i32, DenseIntElementsAttr.get(i32_array, type=vec_i32)) + +# "q" is the equivalent of `long long` in C and requires at least +# 64 bit width integers on both Linux and Windows. +i64_array = array("q", [5, 6, 7, 8]) +i64 = IntegerType.get_signless(64) +vec_i64 = VectorType.get([1, 4], i64) +arith.constant(vec_i64, i64_array) +arith.ConstantOp(vec_i64, DenseIntElementsAttr.get(i64_array, type=vec_i64)) + +f32_array = array("f", [1.0, 2.0, 3.0, 4.0]) +f32 = F32Type.get() +vec_f32 = VectorType.get([4, 1], f32) +arith.constant(vec_f32, f32_array) +arith.ConstantOp(vec_f32, DenseFPElementsAttr.get(f32_array, type=vec_f32)) + +
[llvm-branch-commits] [mlir] 1e73955 - [mlir] Use more C99 comments in C API header files
Author: Alex Zinenko Date: 2021-01-25T19:23:06+01:00 New Revision: 1e739552ee96db4b3f2d792976ea849cb6f23650 URL: https://github.com/llvm/llvm-project/commit/1e739552ee96db4b3f2d792976ea849cb6f23650 DIFF: https://github.com/llvm/llvm-project/commit/1e739552ee96db4b3f2d792976ea849cb6f23650.diff LOG: [mlir] Use more C99 comments in C API header files These were left over from the original reformatting commit. Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D95357 Added: Modified: mlir/include/mlir-c/AffineExpr.h mlir/include/mlir-c/AffineMap.h mlir/include/mlir-c/BuiltinAttributes.h mlir/include/mlir-c/BuiltinTypes.h mlir/include/mlir-c/Diagnostics.h mlir/include/mlir-c/IR.h mlir/include/mlir-c/Pass.h mlir/include/mlir-c/Support.h Removed: diff --git a/mlir/include/mlir-c/AffineExpr.h b/mlir/include/mlir-c/AffineExpr.h index d5c6e7b9f29e..5516f29088e4 100644 --- a/mlir/include/mlir-c/AffineExpr.h +++ b/mlir/include/mlir-c/AffineExpr.h @@ -17,17 +17,16 @@ extern "C" { #endif //===--===// -/** Opaque type declarations. - * - * Types are exposed to C bindings as structs containing opaque pointers. They - * are not supposed to be inspected from C. This allows the underlying - * representation to change without affecting the API users. The use of structs - * instead of typedefs enables some type safety as structs are not implicitly - * convertible to each other. - * - * Instances of these types may or may not own the underlying object. The - * ownership semantics is defined by how an instance of the type was obtained. - */ +// Opaque type declarations. +// +// Types are exposed to C bindings as structs containing opaque pointers. They +// are not supposed to be inspected from C. This allows the underlying +// representation to change without affecting the API users. The use of structs +// instead of typedefs enables some type safety as structs are not implicitly +// convertible to each other. +// +// Instances of these types may or may not own the underlying object. The +// ownership semantics is defined by how an instance of the type was obtained. //===--===// #define DEFINE_C_API_STRUCT(name, storage) \ @@ -54,9 +53,9 @@ inline static bool mlirAffineExprIsNull(MlirAffineExpr affineExpr) { return affineExpr.ptr == NULL; } -/** Prints an affine expression by sending chunks of the string representation - * and forwarding `userData to `callback`. Note that the callback may be called - * several times with consecutive chunks of the string. */ +/// Prints an affine expression by sending chunks of the string representation +/// and forwarding `userData to `callback`. Note that the callback may be called +/// several times with consecutive chunks of the string. MLIR_CAPI_EXPORTED void mlirAffineExprPrint(MlirAffineExpr affineExpr, MlirStringCallback callback, void *userData); @@ -64,17 +63,17 @@ MLIR_CAPI_EXPORTED void mlirAffineExprPrint(MlirAffineExpr affineExpr, /// Prints the affine expression to the standard error stream. MLIR_CAPI_EXPORTED void mlirAffineExprDump(MlirAffineExpr affineExpr); -/** Checks whether the given affine expression is made out of only symbols and - * constants. */ +/// Checks whether the given affine expression is made out of only symbols and +/// constants. MLIR_CAPI_EXPORTED bool mlirAffineExprIsSymbolicOrConstant(MlirAffineExpr affineExpr); -/** Checks whether the given affine expression is a pure affine expression, i.e. - * mul, floordiv, ceildic, and mod is only allowed w.r.t constants. */ +/// Checks whether the given affine expression is a pure affine expression, i.e. +/// mul, floordiv, ceildic, and mod is only allowed w.r.t constants. MLIR_CAPI_EXPORTED bool mlirAffineExprIsPureAffine(MlirAffineExpr affineExpr); -/** Returns the greatest known integral divisor of this affine expression. The - * result is always positive. */ +/// Returns the greatest known integral divisor of this affine expression. The +/// result is always positive. MLIR_CAPI_EXPORTED int64_t mlirAffineExprGetLargestKnownDivisor(MlirAffineExpr affineExpr); @@ -82,8 +81,8 @@ mlirAffineExprGetLargestKnownDivisor(MlirAffineExpr affineExpr); MLIR_CAPI_EXPORTED bool mlirAffineExprIsMultipleOf(MlirAffineExpr affineExpr, int64_t factor); -/** Checks whether the given affine expression involves AffineDimExpr - * 'position'. */ +/// Checks whether the given affine expression involves AffineDimExpr +/// 'position'. MLIR_CAPI_EXPORTED bool mlirAffineExprIsFunctionOfDim(MlirAffineExpr affineExpr,
[llvm-branch-commits] [mlir] f5c7c03 - [mlir] Add C API for IntegerSet
Author: Alex Zinenko Date: 2021-01-25T20:16:22+01:00 New Revision: f5c7c031e2493168b3c2cfea3219e2131cc01483 URL: https://github.com/llvm/llvm-project/commit/f5c7c031e2493168b3c2cfea3219e2131cc01483 DIFF: https://github.com/llvm/llvm-project/commit/f5c7c031e2493168b3c2cfea3219e2131cc01483.diff LOG: [mlir] Add C API for IntegerSet Depends On D95357 Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D95368 Added: mlir/include/mlir-c/IntegerSet.h mlir/include/mlir/CAPI/IntegerSet.h mlir/lib/CAPI/IR/IntegerSet.cpp Modified: mlir/include/mlir/IR/IntegerSet.h mlir/lib/CAPI/IR/CMakeLists.txt mlir/test/CAPI/ir.c Removed: diff --git a/mlir/include/mlir-c/IntegerSet.h b/mlir/include/mlir-c/IntegerSet.h new file mode 100644 index ..058be414d2ee --- /dev/null +++ b/mlir/include/mlir-c/IntegerSet.h @@ -0,0 +1,131 @@ +//===-- mlir-c/IntegerSet.h - C API for MLIR Affine maps --*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM +// Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef MLIR_C_INTEGERSET_H +#define MLIR_C_INTEGERSET_H + +#include "mlir-c/AffineExpr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===--===// +// Opaque type declarations. +// +// Types are exposed to C bindings as structs containing opaque pointers. They +// are not supposed to be inspected from C. This allows the underlying +// representation to change without affecting the API users. The use of structs +// instead of typedefs enables some type safety as structs are not implicitly +// convertible to each other. +// +// Instances of these types may or may not own the underlying object. The +// ownership semantics is defined by how an instance of the type was obtained. +//===--===// + +#define DEFINE_C_API_STRUCT(name, storage) \ + struct name { \ +storage *ptr; \ + }; \ + typedef struct name name + +DEFINE_C_API_STRUCT(MlirIntegerSet, const void); + +#undef DEFINE_C_API_STRUCT + +/// Gets the context in which the given integer set lives. +MLIR_CAPI_EXPORTED MlirContext mlirIntegerSetGetContext(MlirIntegerSet set); + +/// Checks whether an integer set is a null object. +static inline bool mlirIntegerSetIsNull(MlirIntegerSet set) { return !set.ptr; } + +/// Checks if two integer set objects are equal. This is a "shallow" comparison +/// of two objects. Only the sets with some small number of constraints are +/// uniqued and compare equal here. Set objects that represent the same integer +/// set with diff erent constraints may be considered non-equal by this check. +/// Set diff erence followed by an (expensive) emptiness check should be used to +/// check equivalence of the underlying integer sets. +MLIR_CAPI_EXPORTED bool mlirIntegerSetEqual(MlirIntegerSet s1, +MlirIntegerSet s2); + +/// Prints an integer set by sending chunks of the string representation and +/// forwarding `userData to `callback`. Note that the callback may be called +/// several times with consecutive chunks of the string. +MLIR_CAPI_EXPORTED void mlirIntegerSetPrint(MlirIntegerSet set, +MlirStringCallback callback, +void *userData); + +/// Prints an integer set to the standard error stream. +MLIR_CAPI_EXPORTED void mlirIntegerSetDump(MlirIntegerSet set); + +/// Gets or creates a new canonically empty integer set with the give number of +/// dimensions and symbols in the given context. +MLIR_CAPI_EXPORTED MlirIntegerSet mlirIntegerSetEmptyGet(MlirContext context, + intptr_t numDims, + intptr_t numSymbols); + +/// Gets or creates a new integer set in the given context. The set is defined +/// by a list of affine constraints, with the given number of input dimensions +/// and symbols, which are treated as either equalities (eqFlags is 1) or +/// inequalities (eqFlags is 0). Both `constraints` and `eqFlags` are expected +/// to point to at least `numConstraint` consecutive values. +MLIR_CAPI_EXPORTED MlirIntegerSet +mlirIntegerSetGet(MlirContext context, intptr_t numDims, intptr_t numSymbols, + intptr_t numConstraints, const MlirAffineExpr *constraints, +
[llvm-branch-commits] [mlir] 4fa01f7 - [mlir][CAPI] Fix inline function declaration
Author: Vladislav Vinogradov Date: 2021-01-12T17:05:02+01:00 New Revision: 4fa01f72de6cc48a44afe057c04803711160c92d URL: https://github.com/llvm/llvm-project/commit/4fa01f72de6cc48a44afe057c04803711160c92d DIFF: https://github.com/llvm/llvm-project/commit/4fa01f72de6cc48a44afe057c04803711160c92d.diff LOG: [mlir][CAPI] Fix inline function declaration Add `static` keyword, otherwise build fail with linker error for some cases. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D94496 Added: Modified: mlir/include/mlir-c/AffineExpr.h Removed: diff --git a/mlir/include/mlir-c/AffineExpr.h b/mlir/include/mlir-c/AffineExpr.h index ec445682c011..d5c6e7b9f29e 100644 --- a/mlir/include/mlir-c/AffineExpr.h +++ b/mlir/include/mlir-c/AffineExpr.h @@ -50,7 +50,7 @@ MLIR_CAPI_EXPORTED bool mlirAffineExprEqual(MlirAffineExpr lhs, /// Returns `true` if the given affine expression is a null expression. Note /// constant zero is not a null expression. -inline bool mlirAffineExprIsNull(MlirAffineExpr affineExpr) { +inline static bool mlirAffineExprIsNull(MlirAffineExpr affineExpr) { return affineExpr.ptr == NULL; } ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 9667d15 - [mlir] Fix for LIT tests
Author: Vladislav Vinogradov Date: 2021-01-12T17:07:23+01:00 New Revision: 9667d15e7496e6d8c313251f22ac157dbbd0c1c2 URL: https://github.com/llvm/llvm-project/commit/9667d15e7496e6d8c313251f22ac157dbbd0c1c2 DIFF: https://github.com/llvm/llvm-project/commit/9667d15e7496e6d8c313251f22ac157dbbd0c1c2.diff LOG: [mlir] Fix for LIT tests Add `MLIR_SPIRV_CPU_RUNNER_ENABLED` to `llvm_canonicalize_cmake_booleans`. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94407 Added: Modified: mlir/test/CMakeLists.txt Removed: diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index f6d5af141630..293d93268a11 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -12,6 +12,7 @@ llvm_canonicalize_cmake_booleans( MLIR_CUDA_RUNNER_ENABLED MLIR_ROCM_CONVERSIONS_ENABLED MLIR_ROCM_RUNNER_ENABLED + MLIR_SPIRV_CPU_RUNNER_ENABLED MLIR_VULKAN_RUNNER_ENABLED ) ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 7fd1850 - [mlir] Update LLVM dialect type documentation
Author: Alex Zinenko Date: 2021-01-12T22:38:24+01:00 New Revision: 7fd18508134112edb93852c16923a74bfff99cd2 URL: https://github.com/llvm/llvm-project/commit/7fd18508134112edb93852c16923a74bfff99cd2 DIFF: https://github.com/llvm/llvm-project/commit/7fd18508134112edb93852c16923a74bfff99cd2.diff LOG: [mlir] Update LLVM dialect type documentation Recent commits reconfigured LLVM dialect types to use built-in types whenever possible. Update the documentation accordingly. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94485 Added: Modified: mlir/docs/Dialects/LLVM.md Removed: diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md index d232ffab148c..1b85091b0756 100644 --- a/mlir/docs/Dialects/LLVM.md +++ b/mlir/docs/Dialects/LLVM.md @@ -130,9 +130,9 @@ Examples: %3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : vector<4xf32> ``` -Note that constants use built-in types within the initializer definition: MLIR -attributes are typed and the attributes used for constants require a built-in -type. +Note that constants list the type twice. This is an artifact of the LLVM dialect +not using built-in types, which are used for typed MLIR attributes. The syntax +will be reevaluated after considering composite constants. ### Globals @@ -186,33 +186,47 @@ attribute. ## Types -LLVM dialect defines a set of types that correspond to LLVM IR types. The -dialect type system is _closed_: types from other dialects are not allowed -within LLVM dialect aggregate types. This property allows for more concise -custom syntax and ensures easy translation to LLVM IR. - -Similarly to other MLIR context-owned objects, the creation and manipulation of -LLVM dialect types is thread-safe. +LLVM dialect uses built-in types whenever possible and defines a set of +complementary types, which correspond to the LLVM IR types that cannot be +directly represented with built-in types. Similarly to other MLIR context-owned +objects, the creation and manipulation of LLVM dialect types is thread-safe. MLIR does not support module-scoped named type declarations, e.g. `%s = type {i32, i32}` in LLVM IR. Instead, types must be fully specified at each use, except for recursive types where only the first reference to a named type needs -to be fully specified. MLIR type aliases are supported for top-level types, i.e. -they cannot be used inside the type due to type system closedness. +to be fully specified. MLIR [type aliases](LangRef.md#type-aliases) can be used +to achieve more compact syntax. The general syntax of LLVM dialect types is `!llvm.`, followed by a type kind identifier (e.g., `ptr` for pointer or `struct` for structure) and by an optional list of type parameters in angle brackets. The dialect follows MLIR style for types with nested angle brackets and keyword specifiers rather than -using diff erent bracket styles to diff erentiate types. Inside angle brackets, -the `!llvm` prefix is omitted for brevity; thanks to closedness of the type -system, all types are assumed to be defined in the LLVM dialect. For example, -`!llvm.ptr>` is a pointer to a packed structure type -containing an 8-bit and a 32-bit integer. +using diff erent bracket styles to diff erentiate types. Types inside the angle +brackets may omit the `!llvm.` prefix for brevity: the parser first attempts to +find a type (starting with `!` or a built-in type) and falls back to accepting a +keyword. For example, `!llvm.ptr>` and `!llvm.ptr>` are +equivalent, with the latter being the canonical form, and denote a pointer to a +pointer to a 32-bit integer. + +### Built-in Type Compatibility + +LLVM dialect accepts a subset of built-in types that are referred to as _LLVM +dialect-compatible types_. The following types are compatible: -### Simple Types +- Signless integers - `iN` (`IntegerType`). +- Floating point types - `bfloat`, `half`, `float`, `double` (`FloatType`). +- 1D vectors of signless integers or floating point types - `vector` +(`VectorType`). -The following non-parametric types are supported. +Note that only a subset of types that can be represented by a given class is +compatible. For example, signed and unsigned integers are not compatible. LLVM +provides a function, `bool LLVM::isCompatibleType(Type)`, that can be used as a +compatibility check. + +### Additional Simple Types + +The following non-parametric types derived from the LLVM IR are available in the +LLVM dialect: - `!llvm.fp128` (`LLVMFP128Type`) - 128-bit floating-point value as per IEEE-754-2008. @@ -231,19 +245,10 @@ The following non-parametric types are supported. These types represent a single value (or an absence thereof in case of `void`) and correspond to their LLVM IR counterparts. -### Parametric Types - - Integer Types +### Additional Parametric Types -Integer types are parametric in
[llvm-branch-commits] [mlir] ed205f6 - [mlir] Update doc to omit the usage of LLVMIntegerType
Author: lewuathe Date: 2021-01-14T09:29:24+01:00 New Revision: ed205f63b4a288ccbffc9af58333d09a7cec40dc URL: https://github.com/llvm/llvm-project/commit/ed205f63b4a288ccbffc9af58333d09a7cec40dc DIFF: https://github.com/llvm/llvm-project/commit/ed205f63b4a288ccbffc9af58333d09a7cec40dc.diff LOG: [mlir] Update doc to omit the usage of LLVMIntegerType Since [[ https://reviews.llvm.org/D94178 | the LLVMIntegerType was replaced with build-in integer type ]], the usage in the tutorial should be also updated accordingly. We need to update chapter 6 for Toy tutorial specifically. See: https://reviews.llvm.org/D94178 Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D94651 Added: Modified: mlir/docs/Tutorials/Toy/Ch-6.md Removed: diff --git a/mlir/docs/Tutorials/Toy/Ch-6.md b/mlir/docs/Tutorials/Toy/Ch-6.md index 1093ae9fe2ba..bddd93688ddb 100644 --- a/mlir/docs/Tutorials/Toy/Ch-6.md +++ b/mlir/docs/Tutorials/Toy/Ch-6.md @@ -37,9 +37,9 @@ static FlatSymbolRefAttr getOrInsertPrintf(PatternRewriter &rewriter, // Create a function declaration for printf, the signature is: // * `i32 (i8*, ...)` - auto llvmI32Ty = LLVM::LLVMIntegerType::get(context, 32); + auto llvmI32Ty = IntegerType::get(context, 32); auto llvmI8PtrTy = - LLVM::LLVMPointerType::get(LLVM::LLVMIntegerType::get(context, 8)); + LLVM::LLVMPointerType::get(IntegerType::get(context, 8)); auto llvmFnType = LLVM::LLVMFunctionType::get(llvmI32Ty, llvmI8PtrTy, /*isVarArg=*/true); ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 6ebeba8 - Support emptiness checks for unbounded FlatAffineConstraints.
Author: Arjun P Date: 2021-01-14T19:33:37+01:00 New Revision: 6ebeba88f51959d763a8f274cdfecea46d51d28c URL: https://github.com/llvm/llvm-project/commit/6ebeba88f51959d763a8f274cdfecea46d51d28c DIFF: https://github.com/llvm/llvm-project/commit/6ebeba88f51959d763a8f274cdfecea46d51d28c.diff LOG: Support emptiness checks for unbounded FlatAffineConstraints. With this, we have complete support for emptiness checks. This also paves the way for future support to check if two FlatAffineConstraints are equal. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D94272 Added: mlir/include/mlir/Analysis/LinearTransform.h mlir/lib/Analysis/LinearTransform.cpp mlir/unittests/Analysis/LinearTransformTest.cpp Modified: mlir/include/mlir/Analysis/AffineStructures.h mlir/include/mlir/Analysis/Presburger/Fraction.h mlir/include/mlir/Analysis/Presburger/Matrix.h mlir/include/mlir/Analysis/Presburger/Simplex.h mlir/lib/Analysis/AffineStructures.cpp mlir/lib/Analysis/CMakeLists.txt mlir/lib/Analysis/Presburger/CMakeLists.txt mlir/lib/Analysis/Presburger/Matrix.cpp mlir/lib/Analysis/Presburger/Simplex.cpp mlir/unittests/Analysis/AffineStructuresTest.cpp mlir/unittests/Analysis/CMakeLists.txt Removed: diff --git a/mlir/include/mlir/Analysis/AffineStructures.h b/mlir/include/mlir/Analysis/AffineStructures.h index 25071db100e3..fa80db7d4b63 100644 --- a/mlir/include/mlir/Analysis/AffineStructures.h +++ b/mlir/include/mlir/Analysis/AffineStructures.h @@ -13,6 +13,7 @@ #ifndef MLIR_ANALYSIS_AFFINE_STRUCTURES_H #define MLIR_ANALYSIS_AFFINE_STRUCTURES_H +#include "mlir/Analysis/Presburger/Matrix.h" #include "mlir/IR/AffineExpr.h" #include "mlir/IR/OpDefinition.h" #include "mlir/Support/LogicalResult.h" @@ -153,6 +154,12 @@ class FlatAffineConstraints { /// false if a solution exists or all tests were inconclusive. bool isIntegerEmpty() const; + // Returns a matrix where each row is a vector along which the polytope is + // bounded. The span of the returned vectors is guaranteed to contain all + // such vectors. The returned vectors are NOT guaranteed to be linearly + // independent. This function should not be called on empty sets. + Matrix getBoundedDirections() const; + /// Find a sample point satisfying the constraints. This uses a branch and /// bound algorithm with generalized basis reduction, which always works if /// the set is bounded. This should not be called for unbounded sets. diff --git a/mlir/include/mlir/Analysis/LinearTransform.h b/mlir/include/mlir/Analysis/LinearTransform.h new file mode 100644 index ..0850f5a00609 --- /dev/null +++ b/mlir/include/mlir/Analysis/LinearTransform.h @@ -0,0 +1,48 @@ +//===- LinearTransform.h - MLIR LinearTransform Class ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Support for linear transforms and applying them to FlatAffineConstraints. +// +//===--===// + +#ifndef MLIR_ANALYSIS_LINEARTRANSFORM_H +#define MLIR_ANALYSIS_LINEARTRANSFORM_H + +#include "mlir/Analysis/AffineStructures.h" +#include "mlir/Analysis/Presburger/Matrix.h" +#include "llvm/ADT/SmallVector.h" + +namespace mlir { + +class LinearTransform { +public: + explicit LinearTransform(Matrix &&oMatrix); + explicit LinearTransform(const Matrix &oMatrix); + + // Returns a linear transform T such that MT is M in column echelon form. + // Also returns the number of non-zero columns in MT. + // + // Specifically, T is such that in every column the first non-zero row is + // strictly below that of the previous column, and all columns which have only + // zeros are at the end. + static std::pair + makeTransformToColumnEchelon(Matrix m); + + // Returns a FlatAffineConstraints having a constraint vector vT for every + // constraint vector v in fac, where T is this transform. + FlatAffineConstraints applyTo(const FlatAffineConstraints &fac); + + // Post-multiply the given vector v with this transform, say T, returning vT. + SmallVector applyTo(ArrayRef v); + +private: + Matrix matrix; +}; + +} // namespace mlir +#endif // MLIR_ANALYSIS_LINEARTRANSFORM_H diff --git a/mlir/include/mlir/Analysis/Presburger/Fraction.h b/mlir/include/mlir/Analysis/Presburger/Fraction.h index 09996c486ef3..61b0915e559e 100644 --- a/mlir/include/mlir/Analysis/Presburger/Fraction.h +++ b/mlir/include/mlir/Analysis/Presburger/Fraction.h @@ -64,6 +64,8 @@ inline bool operator<=(Fraction x, Fraction y) { return compare(x, y) <= 0; } inline bool operator==(Fraction x, Fraction y)
[llvm-branch-commits] [mlir] aca240b - [mlir] Fix cross-compilation (Linalg ODS gen)
Author: Vladislav Vinogradov Date: 2021-01-18T11:57:55+01:00 New Revision: aca240b4f69e908b31e30b7ccece3c5b1d58426e URL: https://github.com/llvm/llvm-project/commit/aca240b4f69e908b31e30b7ccece3c5b1d58426e DIFF: https://github.com/llvm/llvm-project/commit/aca240b4f69e908b31e30b7ccece3c5b1d58426e.diff LOG: [mlir] Fix cross-compilation (Linalg ODS gen) Use cross-compilation approach for `mlir-linalg-ods-gen` application similar to TblGen tools. Reviewed By: nicolasvasilache Differential Revision: https://reviews.llvm.org/D94598 Added: Modified: mlir/CMakeLists.txt mlir/include/mlir/Dialect/Linalg/IR/CMakeLists.txt mlir/tools/CMakeLists.txt mlir/tools/mlir-linalg-ods-gen/CMakeLists.txt Removed: diff --git a/mlir/CMakeLists.txt b/mlir/CMakeLists.txt index 2cf37753ea5c..cbae5fd54823 100644 --- a/mlir/CMakeLists.txt +++ b/mlir/CMakeLists.txt @@ -98,6 +98,7 @@ include_directories( ${MLIR_INCLUDE_DIR}) # MLIR_TABLEGEN_EXE in PARENT_SCOPE which gets lost if that folder is included # from another directory like tools add_subdirectory(tools/mlir-tblgen) +add_subdirectory(tools/mlir-linalg-ods-gen) add_subdirectory(include/mlir) add_subdirectory(lib) diff --git a/mlir/include/mlir/Dialect/Linalg/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/Linalg/IR/CMakeLists.txt index fe67dcb7a660..09db72806565 100644 --- a/mlir/include/mlir/Dialect/Linalg/IR/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/Linalg/IR/CMakeLists.txt @@ -11,17 +11,19 @@ function(add_linalg_ods_gen tc_filename output_file) PROPERTIES GENERATED TRUE) add_custom_command( OUTPUT ${GEN_ODS_FILE} ${GEN_CPP_FILE} -COMMAND mlir-linalg-ods-gen -gen-ods-decl ${TC_SOURCE} > ${GEN_ODS_FILE} -COMMAND mlir-linalg-ods-gen -gen-impl ${TC_SOURCE} > ${GEN_CPP_FILE} +COMMAND ${MLIR_LINALG_ODS_GEN_EXE} -gen-ods-decl ${TC_SOURCE} > ${GEN_ODS_FILE} +COMMAND ${MLIR_LINALG_ODS_GEN_EXE} -gen-impl ${TC_SOURCE} > ${GEN_CPP_FILE} MAIN_DEPENDENCY ${TC_SOURCE} DEPENDS -mlir-linalg-ods-gen +${MLIR_LINALG_ODS_GEN_EXE} +${MLIR_LINALG_ODS_GEN_TARGET} VERBATIM) add_custom_target( MLIR${output_file}IncGen DEPENDS -mlir-linalg-ods-gen +${MLIR_LINALG_ODS_GEN_EXE} +${MLIR_LINALG_ODS_GEN_TARGET} ${GEN_ODS_FILE} ${GEN_CPP_FILE}) endfunction() diff --git a/mlir/tools/CMakeLists.txt b/mlir/tools/CMakeLists.txt index ab59514ef6a7..3a60ae25548e 100644 --- a/mlir/tools/CMakeLists.txt +++ b/mlir/tools/CMakeLists.txt @@ -1,10 +1,9 @@ add_subdirectory(mlir-cuda-runner) add_subdirectory(mlir-cpu-runner) -add_subdirectory(mlir-linalg-ods-gen) add_subdirectory(mlir-opt) add_subdirectory(mlir-reduce) add_subdirectory(mlir-rocm-runner) add_subdirectory(mlir-shlib) add_subdirectory(mlir-spirv-cpu-runner) add_subdirectory(mlir-translate) -add_subdirectory(mlir-vulkan-runner) \ No newline at end of file +add_subdirectory(mlir-vulkan-runner) diff --git a/mlir/tools/mlir-linalg-ods-gen/CMakeLists.txt b/mlir/tools/mlir-linalg-ods-gen/CMakeLists.txt index bc9a0c1f310a..7a0f79798268 100644 --- a/mlir/tools/mlir-linalg-ods-gen/CMakeLists.txt +++ b/mlir/tools/mlir-linalg-ods-gen/CMakeLists.txt @@ -10,3 +10,18 @@ target_link_libraries(mlir-linalg-ods-gen PRIVATE MLIRSupport MLIRIR ) + +set(MLIR_LINALG_ODS_GEN_EXE mlir-linalg-ods-gen PARENT_SCOPE) +set(MLIR_LINALG_ODS_GEN_TARGET mlir-linalg-ods-gen PARENT_SCOPE) + +if(LLVM_USE_HOST_TOOLS) + build_native_tool(mlir-linalg-ods-gen MLIR_LINALG_ODS_GEN_EXE DEPENDS mlir-linalg-ods-gen) + set(MLIR_LINALG_ODS_GEN_EXE ${MLIR_LINALG_ODS_GEN_EXE} PARENT_SCOPE) + + add_custom_target(mlir-linalg-ods-gen-host DEPENDS ${MLIR_LINALG_ODS_GEN_EXE}) + set(MLIR_LINALG_ODS_GEN_TARGET mlir-linalg-ods-gen-host DEPENDS PARENT_SCOPE) + + if(NOT LLVM_BUILD_UTILS) +set_target_properties(mlir-linalg-ods-gen PROPERTIES EXCLUDE_FROM_ALL ON) + endif() +endif() ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 9a60ad2 - [mlir] Clarify docs around LLVM dialect-compatible types
Author: Alex Zinenko Date: 2021-01-19T13:42:16+01:00 New Revision: 9a60ad216d2fa2e9701849922bfb0db9917f9c93 URL: https://github.com/llvm/llvm-project/commit/9a60ad216d2fa2e9701849922bfb0db9917f9c93 DIFF: https://github.com/llvm/llvm-project/commit/9a60ad216d2fa2e9701849922bfb0db9917f9c93.diff LOG: [mlir] Clarify docs around LLVM dialect-compatible types Explicitly mention that there is exactly one MLIR type that corresponds to a given LLVM IR type. Added: Modified: mlir/docs/Dialects/LLVM.md Removed: diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md index b396cdebf067..521c5f4c328b 100644 --- a/mlir/docs/Dialects/LLVM.md +++ b/mlir/docs/Dialects/LLVM.md @@ -224,6 +224,11 @@ compatible. For example, signed and unsigned integers are not compatible. LLVM provides a function, `bool LLVM::isCompatibleType(Type)`, that can be used as a compatibility check. +Each LLVM IR type corresponds to *exactly one* MLIR type, either built-in or +LLVM dialect type. For example, because `i32` is LLVM-compatible, there is no +`!llvm.i32` type. However, `!llvm.ptr` is defined in the LLVM dialect as +there is no corresponding built-in type. + ### Additional Simple Types The following non-parametric types derived from the LLVM IR are available in the ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 74438ef - [mlir] Use thread_local stack in LLVM dialect type parsing and printing
Author: Alex Zinenko Date: 2021-01-06T12:05:24+01:00 New Revision: 74438eff511e71dc33841546d89cb34206551d55 URL: https://github.com/llvm/llvm-project/commit/74438eff511e71dc33841546d89cb34206551d55 DIFF: https://github.com/llvm/llvm-project/commit/74438eff511e71dc33841546d89cb34206551d55.diff LOG: [mlir] Use thread_local stack in LLVM dialect type parsing and printing LLVM dialect type parsing and printing have been using a local stack object forwarded between recursive functions responsible for parsing or printing specific types. This stack is necessary to intercept (mutually) recursive structure types and avoid inifinite recursion. This approach works only thanks to the closedness of the LLVM dialect type system: types that don't belong to the dialect are not allowed. Switch the approach to using a `thread_local` stack inside the functions parsing the structure types. This makes the code slightly cleaner by avoiding the need to pass the stack object around and, more importantly, makes it possible to reconsider the closedness of the LLVM dialect type system. As a nice side effect of this change, container LLVM dialect types now support type aliases in their body (although it is currently impossible to also use the alises when printing). Depends On D93713 Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D93714 Added: Modified: mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp mlir/test/Dialect/LLVMIR/types-invalid.mlir mlir/test/Dialect/LLVMIR/types.mlir Removed: diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp index 3d72e254f338..08c00befcf18 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp @@ -9,6 +9,7 @@ #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/TypeSwitch.h" @@ -19,8 +20,14 @@ using namespace mlir::LLVM; // Printing. //===--===// -static void printTypeImpl(llvm::raw_ostream &os, Type type, - llvm::SetVector &stack); +/// If the given type is compatible with the LLVM dialect, prints it using +/// internal functions to avoid getting a verbose `!llvm` prefix. Otherwise +/// prints it as usual. +static void dispatchPrint(DialectAsmPrinter &printer, Type type) { + if (isCompatibleType(type)) +return mlir::LLVM::detail::printType(type, printer); + printer.printType(type); +} /// Returns the keyword to use for the given type. static StringRef getTypeKeyword(Type type) { @@ -48,76 +55,79 @@ static StringRef getTypeKeyword(Type type) { }); } -/// Prints the body of a structure type. Uses `stack` to avoid printing -/// recursive structs indefinitely. -static void printStructTypeBody(llvm::raw_ostream &os, LLVMStructType type, -llvm::SetVector &stack) { - if (type.isIdentified() && type.isOpaque()) { -os << "opaque"; -return; - } - - if (type.isPacked()) -os << "packed "; - - // Put the current type on stack to avoid infinite recursion. - os << '('; - if (type.isIdentified()) -stack.insert(type.getName()); - llvm::interleaveComma(type.getBody(), os, [&](Type subtype) { -printTypeImpl(os, subtype, stack); +/// Prints a structure type. Keeps track of known struct names to handle self- +/// or mutually-referring structs without falling into infinite recursion. +static void printStructType(DialectAsmPrinter &printer, LLVMStructType type) { + // This keeps track of the names of identified structure types that are + // currently being printed. Since such types can refer themselves, this + // tracking is necessary to stop the recursion: the current function may be + // called recursively from DialectAsmPrinter::printType after the appropriate + // dispatch. We maintain the invariant of this storage being modified + // exclusively in this function, and at most one name being added per call. + // TODO: consider having such functionality inside DialectAsmPrinter. + thread_local llvm::SetVector knownStructNames; + unsigned stackSize = knownStructNames.size(); + (void)stackSize; + auto guard = llvm::make_scope_exit([&]() { +assert(knownStructNames.size() == stackSize && + "malformed identified stack when printing recursive structs"); }); - if (type.isIdentified()) -stack.pop_back(); - os << ')'; -} -/// Prints a structure type. Uses `stack` to keep track of the identifiers of -/// the structs being printed. Checks if the identifier of a struct is contained -/// in `stack`, i.e. whether a self-reference to a recursive stack is being -/// printed, and only prints the name to avoid infinite recursio
[llvm-branch-commits] [mlir] 10164a2 - [mlir] Refactor translation of OpenMP dialect ops to LLVM IR
Author: Alex Zinenko Date: 2021-01-07T13:33:50+01:00 New Revision: 10164a2e50b4d7064bd02e7403aae6dd319cdd64 URL: https://github.com/llvm/llvm-project/commit/10164a2e50b4d7064bd02e7403aae6dd319cdd64 DIFF: https://github.com/llvm/llvm-project/commit/10164a2e50b4d7064bd02e7403aae6dd319cdd64.diff LOG: [mlir] Refactor translation of OpenMP dialect ops to LLVM IR The original implementation of the OpenMP dialect to LLVM IR translation has been relying on a stack of insertion points for delayed insertion of branch instructions that correspond to terminator ops. This is an intrusive into ModuleTranslation and makes the translation non-local. A recent addition of the WsLoop translation exercised another approach where the parent op is responsible for converting terminators of all blocks in its regions. Use this approach for other OpenMP dialect operations with regions, remove the stack and deduplicate the code for converting such regions. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D94086 Added: Modified: mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h mlir/lib/Target/LLVMIR/ModuleTranslation.cpp Removed: diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 7691adfeef14..4a1871cac4dc 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -93,11 +93,11 @@ class ModuleTranslation { llvm::IRBuilder<> &builder); virtual LogicalResult convertOmpMaster(Operation &op, llvm::IRBuilder<> &builder); - void convertOmpOpRegions(Region ®ion, + void convertOmpOpRegions(Region ®ion, StringRef blockName, DenseMap &valueMapping, DenseMap &blockMapping, - llvm::Instruction *codeGenIPBBTI, - llvm::BasicBlock &continuationIP, + llvm::BasicBlock &sourceBlock, + llvm::BasicBlock &continuationBlock, llvm::IRBuilder<> &builder, LogicalResult &bodyGenStatus); virtual LogicalResult convertOmpWsLoop(Operation &opInst, @@ -121,7 +121,8 @@ class ModuleTranslation { LogicalResult convertFunctions(); LogicalResult convertGlobals(); LogicalResult convertOneFunction(LLVMFuncOp func); - LogicalResult convertBlock(Block &bb, bool ignoreArguments); + LogicalResult convertBlock(Block &bb, bool ignoreArguments, + llvm::IRBuilder<> &builder); llvm::Constant *getLLVMConstant(llvm::Type *llvmType, Attribute attr, Location loc); @@ -134,14 +135,11 @@ class ModuleTranslation { /// Builder for LLVM IR generation of OpenMP constructs. std::unique_ptr ompBuilder; + /// Precomputed pointer to OpenMP dialect. Note this can be nullptr if the /// OpenMP dialect hasn't been loaded (it is always loaded if there are OpenMP /// operations in the module though). const Dialect *ompDialect; - /// Stack which stores the target block to which a branch a must be added when - /// a terminator is seen. A stack is required to handle nested OpenMP parallel - /// regions. - SmallVector ompContinuationIPStack; /// Mappings between llvm.mlir.global definitions and corresponding globals. DenseMap globalsMapping; diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index da9c734fbd80..5ffb11e76a93 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -413,24 +413,11 @@ ModuleTranslation::convertOmpParallel(Operation &opInst, auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, llvm::BasicBlock &continuationIP) { -llvm::LLVMContext &llvmContext = llvmModule->getContext(); - -llvm::BasicBlock *codeGenIPBB = codeGenIP.getBlock(); -llvm::Instruction *codeGenIPBBTI = codeGenIPBB->getTerminator(); -ompContinuationIPStack.push_back(&continuationIP); - -// ParallelOp has only `1` region associated with it. +// ParallelOp has only one region associated with it. auto ®ion = cast(opInst).getRegion(); -for (auto &bb : region) { - auto *llvmBB = llvm::BasicBlock::Create( - llvmContext, "omp.par.region", codeGenIP.getBlock()->getParent()); - blockMapping[&bb] = llvmBB; -} - -convertOmpOpRegions(region, valueMapping, blockMapping, codeGenIPBBTI, -continuationIP, builder, bodyGenStatus); -ompContinuationIPStack.pop_back(); - +convertOmpOpRegions(region, "omp.par.region", valueMapping, blockMapping, +*codeGenIP.getBlock(
[llvm-branch-commits] [mlir] c1d58c2 - [mlir] Add fastmath flags support to some LLVM dialect ops
Author: Ivan Butygin Date: 2021-01-07T14:00:09+01:00 New Revision: c1d58c2b0023cd41f0da128f5190fa887d8f6c69 URL: https://github.com/llvm/llvm-project/commit/c1d58c2b0023cd41f0da128f5190fa887d8f6c69 DIFF: https://github.com/llvm/llvm-project/commit/c1d58c2b0023cd41f0da128f5190fa887d8f6c69.diff LOG: [mlir] Add fastmath flags support to some LLVM dialect ops Add fastmath enum, attributes to some llvm dialect ops, `FastmathFlagsInterface` op interface, and `translateModuleToLLVMIR` support. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D92485 Added: mlir/include/mlir/Dialect/LLVMIR/LLVMOpsInterfaces.td Modified: mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp mlir/lib/Dialect/LLVMIR/CMakeLists.txt mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp mlir/lib/Target/LLVMIR/ModuleTranslation.cpp mlir/test/Dialect/LLVMIR/roundtrip.mlir mlir/test/Target/llvmir.mlir Removed: diff --git a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt index 6166f3632607..29cef3f0032d 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt @@ -10,6 +10,8 @@ add_public_tablegen_target(MLIRLLVMOpsIncGen) add_mlir_doc(LLVMOps -gen-op-doc LLVMOps Dialects/) +add_mlir_interface(LLVMOpsInterfaces) + set(LLVM_TARGET_DEFINITIONS LLVMOps.td) mlir_tablegen(LLVMConversions.inc -gen-llvmir-conversions) mlir_tablegen(LLVMConversionEnumsToLLVM.inc -gen-enum-to-llvmir-conversions) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h index 630bad4914b1..22ff1517f77b 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h @@ -29,6 +29,7 @@ #include "llvm/IR/Type.h" #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.h.inc" +#include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.h.inc" namespace llvm { class Type; @@ -46,8 +47,23 @@ class LLVMDialect; namespace detail { struct LLVMTypeStorage; struct LLVMDialectImpl; +struct BitmaskEnumStorage; } // namespace detail +/// An attribute that specifies LLVM instruction fastmath flags. +class FMFAttr : public Attribute::AttrBase { +public: + using Base::Base; + + static FMFAttr get(FastmathFlags flags, MLIRContext *context); + + FastmathFlags getFlags() const; + + void print(DialectAsmPrinter &p) const; + static Attribute parse(DialectAsmParser &parser); +}; + } // namespace LLVM } // namespace mlir diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 428ca6783afd..53c42540aa48 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -14,10 +14,39 @@ #define LLVMIR_OPS include "mlir/Dialect/LLVMIR/LLVMOpBase.td" +include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.td" include "mlir/IR/SymbolInterfaces.td" include "mlir/Interfaces/ControlFlowInterfaces.td" include "mlir/Interfaces/SideEffectInterfaces.td" +def FMFnnan : BitEnumAttrCase<"nnan", 0x1>; +def FMFninf : BitEnumAttrCase<"ninf", 0x2>; +def FMFnsz : BitEnumAttrCase<"nsz", 0x4>; +def FMFarcp : BitEnumAttrCase<"arcp", 0x8>; +def FMFcontract : BitEnumAttrCase<"contract", 0x10>; +def FMFafn : BitEnumAttrCase<"afn", 0x20>; +def FMFreassoc : BitEnumAttrCase<"reassoc", 0x40>; +def FMFfast : BitEnumAttrCase<"fast", 0x80>; + +def FastmathFlags : BitEnumAttr< +"FastmathFlags", +"LLVM fastmath flags", +[FMFnnan, FMFninf, FMFnsz, FMFarcp, FMFcontract, FMFafn, FMFreassoc, FMFfast +]> { + let cppNamespace = "::mlir::LLVM"; +} + +def LLVM_FMFAttr : DialectAttr< +LLVM_Dialect, +CPred<"$_self.isa<::mlir::LLVM::FMFAttr>()">, +"LLVM fastmath flags"> { + let storageType = "::mlir::LLVM::FMFAttr"; + let returnType = "::mlir::LLVM::FastmathFlags"; + let convertFromStorage = "$_self.getFlags()"; + let constBuilderCall = + "::mlir::LLVM::FMFAttr::get($0, $_builder.getContext())"; +} + class LLVM_Builder { string llvmBuilder = builder; } @@ -77,29 +106,35 @@ class LLVM_ArithmeticOpBase, LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> { - let arguments = (ins LLVM_ScalarOrVectorOf:$lhs, - LLVM_ScalarOrVectorOf:$rhs); + dag commonArgs = (ins LLVM_ScalarOrVectorOf:$lhs, +LLVM_ScalarOrVectorOf:$rhs); let results = (outs LLVM_ScalarOrVectorOf:$res); let builders = [LLVM_OneResultOpBuilder]; - let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($res)"; + let assemblyFormat = "$lhs `,` $rhs custom(attr-dict) `:` type($res)"; } class LLV
[llvm-branch-commits] [mlir] a7cbc32 - [mlir] remove a use of deprecated OpState::setAttr
Author: Alex Zinenko Date: 2021-01-07T14:20:36+01:00 New Revision: a7cbc32a916a64e9f61106956ed3866a6086ae6b URL: https://github.com/llvm/llvm-project/commit/a7cbc32a916a64e9f61106956ed3866a6086ae6b DIFF: https://github.com/llvm/llvm-project/commit/a7cbc32a916a64e9f61106956ed3866a6086ae6b.diff LOG: [mlir] remove a use of deprecated OpState::setAttr Added: Modified: mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp Removed: diff --git a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp index 5e270881656c..51f34661bece 100644 --- a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp +++ b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp @@ -1894,7 +1894,7 @@ struct ConstantOpLowering : public ConvertOpToLLVMPattern { for (const NamedAttribute &attr : op->getAttrs()) { if (attr.first.strref() == "value") continue; -newOp.setAttr(attr.first, attr.second); +newOp->setAttr(attr.first, attr.second); } rewriter.replaceOp(op, newOp->getResults()); return success(); ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 906efee - [mlir] don't match the text produced only in debug mode in Python tests
Author: Alex Zinenko Date: 2021-01-07T19:57:28+01:00 New Revision: 906efeec0a471be522588bd7cbb7f61459b2b437 URL: https://github.com/llvm/llvm-project/commit/906efeec0a471be522588bd7cbb7f61459b2b437 DIFF: https://github.com/llvm/llvm-project/commit/906efeec0a471be522588bd7cbb7f61459b2b437.diff LOG: [mlir] don't match the text produced only in debug mode in Python tests Some Python bindings tests were using FileCheck to match parts of the error description produced only in the debug compilation mode. Remove these parts (but keep the main message) to ensure tests also pass when running them in the release compilation mode. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94221 Added: Modified: mlir/test/Bindings/Python/ir_attributes.py mlir/test/Bindings/Python/ir_operation.py Removed: diff --git a/mlir/test/Bindings/Python/ir_attributes.py b/mlir/test/Bindings/Python/ir_attributes.py index ce85dc3cf87a..91b0a92e989f 100644 --- a/mlir/test/Bindings/Python/ir_attributes.py +++ b/mlir/test/Bindings/Python/ir_attributes.py @@ -371,7 +371,7 @@ def testArrayAttr(): try: ArrayAttr.get([42]) except RuntimeError as e: - # CHECK: Error: Invalid attribute when attempting to create an ArrayAttribute (Unable to cast Python instance of type to C++ type 'mlir::python::PyAttribute') + # CHECK: Error: Invalid attribute when attempting to create an ArrayAttribute print("Error: ", e) run(testArrayAttr) diff --git a/mlir/test/Bindings/Python/ir_operation.py b/mlir/test/Bindings/Python/ir_operation.py index ba54e83f65e8..034b28ec25bf 100644 --- a/mlir/test/Bindings/Python/ir_operation.py +++ b/mlir/test/Bindings/Python/ir_operation.py @@ -566,17 +566,17 @@ def testCreateWithInvalidAttributes(): try: Operation.create("module", attributes={None:StringAttr.get("name")}) except Exception as e: - # CHECK: Invalid attribute key (not a string) when attempting to create the operation "module" (Unable to cast Python instance of type to C++ type + # CHECK: Invalid attribute key (not a string) when attempting to create the operation "module" print(e) try: Operation.create("module", attributes={42:StringAttr.get("name")}) except Exception as e: - # CHECK: Invalid attribute key (not a string) when attempting to create the operation "module" (Unable to cast Python instance of type to C++ type + # CHECK: Invalid attribute key (not a string) when attempting to create the operation "module" print(e) try: Operation.create("module", attributes={"some_key":ctx}) except Exception as e: - # CHECK: Invalid attribute value for the key "some_key" when attempting to create the operation "module" (Unable to cast Python instance of type to C++ type 'mlir::python::PyAttribute') + # CHECK: Invalid attribute value for the key "some_key" when attempting to create the operation "module" print(e) try: Operation.create("module", attributes={"some_key":None}) ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 195ffcd - [MLIR][NFC] remove unnecessary includes form tablegen command
Author: Shivam Gupta Date: 2021-01-08T14:25:52+01:00 New Revision: 195ffcd890f648187cd110965a419c01d6488f66 URL: https://github.com/llvm/llvm-project/commit/195ffcd890f648187cd110965a419c01d6488f66 DIFF: https://github.com/llvm/llvm-project/commit/195ffcd890f648187cd110965a419c01d6488f66.diff LOG: [MLIR][NFC] remove unnecessary includes form tablegen command With [[ https://reviews.llvm.org/D77156 | D77156 ]] includes are not needed here. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D94216 Added: Modified: mlir/cmake/modules/AddMLIR.cmake Removed: diff --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake index 9709615c7d66..4cfd351d9758 100644 --- a/mlir/cmake/modules/AddMLIR.cmake +++ b/mlir/cmake/modules/AddMLIR.cmake @@ -29,7 +29,7 @@ endfunction() # Generate Documentation function(add_mlir_doc doc_filename command output_file output_directory) set(LLVM_TARGET_DEFINITIONS ${doc_filename}.td) - tablegen(MLIR ${output_file}.md ${command} "-I${MLIR_MAIN_INCLUDE_DIR}" "-I${MLIR_INCLUDE_DIR}") + tablegen(MLIR ${output_file}.md ${command}) set(GEN_DOC_FILE ${MLIR_BINARY_DIR}/docs/${output_directory}${output_file}.md) add_custom_command( OUTPUT ${GEN_DOC_FILE} ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 74628c4 - [mlir] Add Python bindings for AffineExpr
Author: Alex Zinenko Date: 2021-01-11T19:57:13+01:00 New Revision: 74628c43053b482f35f0f1e6b4eac743fbe425e5 URL: https://github.com/llvm/llvm-project/commit/74628c43053b482f35f0f1e6b4eac743fbe425e5 DIFF: https://github.com/llvm/llvm-project/commit/74628c43053b482f35f0f1e6b4eac743fbe425e5.diff LOG: [mlir] Add Python bindings for AffineExpr This adds the Python bindings for AffineExpr and a couple of utility functions to the C API. AffineExpr is a top-level context-owned object and is modeled similarly to attributes and types. It is required, e.g., to build layout maps of the built-in memref type. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94225 Added: mlir/test/Bindings/Python/ir_affine_expr.py Modified: mlir/include/mlir-c/AffineExpr.h mlir/include/mlir-c/Bindings/Python/Interop.h mlir/lib/Bindings/Python/IRModules.cpp mlir/lib/Bindings/Python/IRModules.h mlir/lib/CAPI/IR/AffineExpr.cpp mlir/test/CAPI/ir.c Removed: diff --git a/mlir/include/mlir-c/AffineExpr.h b/mlir/include/mlir-c/AffineExpr.h index 93b8e832b44f..2eb8ae03e03d 100644 --- a/mlir/include/mlir-c/AffineExpr.h +++ b/mlir/include/mlir-c/AffineExpr.h @@ -45,6 +45,16 @@ DEFINE_C_API_STRUCT(MlirAffineExpr, const void); MLIR_CAPI_EXPORTED MlirContext mlirAffineExprGetContext(MlirAffineExpr affineExpr); +/// Returns `true` if the two affine expressions are equal. +MLIR_CAPI_EXPORTED bool mlirAffineExprEqual(MlirAffineExpr lhs, +MlirAffineExpr rhs); + +/// Returns `true` if the given affine expression is a null expression. Note +/// constant zero is not a null expression. +inline bool mlirAffineExprIsNull(MlirAffineExpr affineExpr) { + return affineExpr.ptr == NULL; +} + /** Prints an affine expression by sending chunks of the string representation * and forwarding `userData to `callback`. Note that the callback may be called * several times with consecutive chunks of the string. */ @@ -82,6 +92,9 @@ MLIR_CAPI_EXPORTED bool mlirAffineExprIsFunctionOfDim(MlirAffineExpr affineExpr, // Affine Dimension Expression. //===--===// +/// Checks whether the given affine expression is a dimension expression. +MLIR_CAPI_EXPORTED bool mlirAffineExprIsADim(MlirAffineExpr affineExpr); + /// Creates an affine dimension expression with 'position' in the context. MLIR_CAPI_EXPORTED MlirAffineExpr mlirAffineDimExprGet(MlirContext ctx, intptr_t position); @@ -94,6 +107,9 @@ mlirAffineDimExprGetPosition(MlirAffineExpr affineExpr); // Affine Symbol Expression. //===--===// +/// Checks whether the given affine expression is a symbol expression. +MLIR_CAPI_EXPORTED bool mlirAffineExprIsASymbol(MlirAffineExpr affineExpr); + /// Creates an affine symbol expression with 'position' in the context. MLIR_CAPI_EXPORTED MlirAffineExpr mlirAffineSymbolExprGet(MlirContext ctx, intptr_t position); @@ -106,6 +122,9 @@ mlirAffineSymbolExprGetPosition(MlirAffineExpr affineExpr); // Affine Constant Expression. //===--===// +/// Checks whether the given affine expression is a constant expression. +MLIR_CAPI_EXPORTED bool mlirAffineExprIsAConstant(MlirAffineExpr affineExpr); + /// Creates an affine constant expression with 'constant' in the context. MLIR_CAPI_EXPORTED MlirAffineExpr mlirAffineConstantExprGet(MlirContext ctx, int64_t constant); @@ -173,6 +192,9 @@ MLIR_CAPI_EXPORTED MlirAffineExpr mlirAffineCeilDivExprGet(MlirAffineExpr lhs, // Affine Binary Operation Expression. //===--===// +/// Checks whether the given affine expression is binary. +MLIR_CAPI_EXPORTED bool mlirAffineExprIsABinary(MlirAffineExpr affineExpr); + /** Returns the left hand side affine expression of the given affine binary * operation expression. */ MLIR_CAPI_EXPORTED MlirAffineExpr diff --git a/mlir/include/mlir-c/Bindings/Python/Interop.h b/mlir/include/mlir-c/Bindings/Python/Interop.h index ae9d3a84a0a3..d1eda4202345 100644 --- a/mlir/include/mlir-c/Bindings/Python/Interop.h +++ b/mlir/include/mlir-c/Bindings/Python/Interop.h @@ -23,10 +23,12 @@ #include +#include "mlir-c/AffineExpr.h" #include "mlir-c/AffineMap.h" #include "mlir-c/IR.h" #include "mlir-c/Pass.h" +#define MLIR_PYTHON_CAPSULE_AFFINE_EXPR "mlir.ir.AffineExpr._CAPIPtr" #define MLIR_PYTHON_CAPSULE_AFFINE_MAP "mlir.ir.AffineMap._CAPIPtr" #define MLIR_PYTHON_CAPSULE_ATTRIBUTE "mlir.ir.Attribute._CAPIPtr" #define MLIR_PYTHON_CAPSULE_CONTEXT "mlir.ir.C
[llvm-branch-commits] [mlir] e79bd0b - [mlir] More Python bindings for AffineMap
Author: Alex Zinenko Date: 2021-01-11T19:57:15+01:00 New Revision: e79bd0b4f25e68130a2ac273d6508ea322028b61 URL: https://github.com/llvm/llvm-project/commit/e79bd0b4f25e68130a2ac273d6508ea322028b61 DIFF: https://github.com/llvm/llvm-project/commit/e79bd0b4f25e68130a2ac273d6508ea322028b61.diff LOG: [mlir] More Python bindings for AffineMap Now that the bindings for AffineExpr have been added, add more bindings for constructing and inspecting AffineMap that consists of AffineExprs. Depends On D94225 Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94297 Added: Modified: mlir/include/mlir-c/AffineExpr.h mlir/include/mlir-c/AffineMap.h mlir/lib/Bindings/Python/IRModules.cpp mlir/lib/CAPI/IR/AffineMap.cpp mlir/test/Bindings/Python/ir_affine_map.py mlir/test/CAPI/ir.c Removed: diff --git a/mlir/include/mlir-c/AffineExpr.h b/mlir/include/mlir-c/AffineExpr.h index 2eb8ae03e03d..ec445682c011 100644 --- a/mlir/include/mlir-c/AffineExpr.h +++ b/mlir/include/mlir-c/AffineExpr.h @@ -10,7 +10,6 @@ #ifndef MLIR_C_AFFINEEXPR_H #define MLIR_C_AFFINEEXPR_H -#include "mlir-c/AffineMap.h" #include "mlir-c/IR.h" #ifdef __cplusplus diff --git a/mlir/include/mlir-c/AffineMap.h b/mlir/include/mlir-c/AffineMap.h index c52fe6826251..bf0c7c7b5381 100644 --- a/mlir/include/mlir-c/AffineMap.h +++ b/mlir/include/mlir-c/AffineMap.h @@ -10,6 +10,7 @@ #ifndef MLIR_C_AFFINEMAP_H #define MLIR_C_AFFINEMAP_H +#include "mlir-c/AffineExpr.h" #include "mlir-c/IR.h" #ifdef __cplusplus @@ -67,9 +68,18 @@ MLIR_CAPI_EXPORTED MlirAffineMap mlirAffineMapEmptyGet(MlirContext ctx); /** Creates a zero result affine map of the given dimensions and symbols in the * context. The affine map is owned by the context. */ +MLIR_CAPI_EXPORTED MlirAffineMap mlirAffineMapZeroResultGet( +MlirContext ctx, intptr_t dimCount, intptr_t symbolCount); + +/** Creates an affine map with results defined by the given list of affine + * expressions. The map resulting map also has the requested number of input + * dimensions and symbols, regardless of them being used in the results. + */ MLIR_CAPI_EXPORTED MlirAffineMap mlirAffineMapGet(MlirContext ctx, intptr_t dimCount, - intptr_t symbolCount); + intptr_t symbolCount, + intptr_t nAffineExprs, + MlirAffineExpr *affineExprs); /** Creates a single constant result affine map in the context. The affine map * is owned by the context. */ @@ -124,6 +134,10 @@ MLIR_CAPI_EXPORTED intptr_t mlirAffineMapGetNumSymbols(MlirAffineMap affineMap); /// Returns the number of results of the given affine map. MLIR_CAPI_EXPORTED intptr_t mlirAffineMapGetNumResults(MlirAffineMap affineMap); +/// Returns the result at the given position. +MLIR_CAPI_EXPORTED MlirAffineExpr +mlirAffineMapGetResult(MlirAffineMap affineMap, intptr_t pos); + /** Returns the number of inputs (dimensions + symbols) of the given affine * map. */ MLIR_CAPI_EXPORTED intptr_t mlirAffineMapGetNumInputs(MlirAffineMap affineMap); diff --git a/mlir/lib/Bindings/Python/IRModules.cpp b/mlir/lib/Bindings/Python/IRModules.cpp index 2d18a7a488e7..81f84b8152f4 100644 --- a/mlir/lib/Bindings/Python/IRModules.cpp +++ b/mlir/lib/Bindings/Python/IRModules.cpp @@ -11,6 +11,7 @@ #include "Globals.h" #include "PybindUtils.h" +#include "mlir-c/AffineMap.h" #include "mlir-c/Bindings/Python/Interop.h" #include "mlir-c/BuiltinAttributes.h" #include "mlir-c/BuiltinTypes.h" @@ -2943,9 +2944,43 @@ PyAffineExpr PyAffineExpr::createFromCapsule(py::object capsule) { } //-- -// PyAffineMap. +// PyAffineMap and utilities. //-- +namespace { +/// A list of expressions contained in an affine map. Internally these are +/// stored as a consecutive array leading to inexpensive random access. Both +/// the map and the expression are owned by the context so we need not bother +/// with lifetime extension. +class PyAffineMapExprList +: public Sliceable { +public: + static constexpr const char *pyClassName = "AffineExprList"; + + PyAffineMapExprList(PyAffineMap map, intptr_t startIndex = 0, + intptr_t length = -1, intptr_t step = 1) + : Sliceable(startIndex, + length == -1 ? mlirAffineMapGetNumResults(map) : length, + step), +affineMap(map) {} + + intptr_t getNumElements() { return mlirAffineMapGetNumResults(affineMap); } + + PyAffineExpr getElement(intptr_t pos) { +return PyAffineExpr(affineMap.getContext(), +
[llvm-branch-commits] [mlir] 547e3ee - [mlir] Expose MemRef layout in Python bindings
Author: Alex Zinenko Date: 2021-01-11T19:57:16+01:00 New Revision: 547e3eef14a8e75a867dfcc6b45cd1f0547d4e07 URL: https://github.com/llvm/llvm-project/commit/547e3eef14a8e75a867dfcc6b45cd1f0547d4e07 DIFF: https://github.com/llvm/llvm-project/commit/547e3eef14a8e75a867dfcc6b45cd1f0547d4e07.diff LOG: [mlir] Expose MemRef layout in Python bindings This wasn't possible before because there was no support for affine expressions as maps. Now that this support is available, provide the mechanism for constructing maps with a layout and inspecting it. Rework the `get` method on MemRefType in Python to avoid needing an explicit memory space or layout map. Remove the `get_num_maps`, it is too low-level, using the length of the now-avaiable pseudo-list of layout maps is more pythonic. Depends On D94297 Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D94302 Added: Modified: mlir/include/mlir-c/BuiltinTypes.h mlir/lib/Bindings/Python/IRModules.cpp mlir/lib/CAPI/IR/BuiltinTypes.cpp mlir/test/Bindings/Python/ir_types.py Removed: diff --git a/mlir/include/mlir-c/BuiltinTypes.h b/mlir/include/mlir-c/BuiltinTypes.h index 77898be41565..9712d58ad87a 100644 --- a/mlir/include/mlir-c/BuiltinTypes.h +++ b/mlir/include/mlir-c/BuiltinTypes.h @@ -225,7 +225,13 @@ MLIR_CAPI_EXPORTED bool mlirTypeIsAUnrankedMemRef(MlirType type); * same context as element type. The type is owned by the context. */ MLIR_CAPI_EXPORTED MlirType mlirMemRefTypeGet( MlirType elementType, intptr_t rank, const int64_t *shape, intptr_t numMaps, -MlirAttribute const *affineMaps, unsigned memorySpace); +MlirAffineMap const *affineMaps, unsigned memorySpace); + +/** Same as "mlirMemRefTypeGet" but returns a nullptr-wrapping MlirType o + * illegal arguments, emitting appropriate diagnostics. */ +MLIR_CAPI_EXPORTED MlirType mlirMemRefTypeGetChecked( +MlirType elementType, intptr_t rank, const int64_t *shape, intptr_t numMaps, +MlirAffineMap const *affineMaps, unsigned memorySpace, MlirLocation loc); /** Creates a MemRef type with the given rank, shape, memory space and element * type in the same context as the element type. The type has no affine maps, diff --git a/mlir/lib/Bindings/Python/IRModules.cpp b/mlir/lib/Bindings/Python/IRModules.cpp index 81f84b8152f4..218099bedc6f 100644 --- a/mlir/lib/Bindings/Python/IRModules.cpp +++ b/mlir/lib/Bindings/Python/IRModules.cpp @@ -2535,6 +2535,8 @@ class PyUnrankedTensorType } }; +class PyMemRefLayoutMapList; + /// Ranked MemRef Type subclass - MemRefType. class PyMemRefType : public PyConcreteType { public: @@ -2542,16 +2544,22 @@ class PyMemRefType : public PyConcreteType { static constexpr const char *pyClassName = "MemRefType"; using PyConcreteType::PyConcreteType; + PyMemRefLayoutMapList getLayout(); + static void bindDerived(ClassTy &c) { -// TODO: Add mlirMemRefTypeGet and mlirMemRefTypeGetAffineMap binding -// once the affine map binding is completed. c.def_static( - "get_contiguous_memref", - // TODO: Make the location optional and create a default location. + "get", [](PyType &elementType, std::vector shape, -unsigned memorySpace, DefaultingPyLocation loc) { - MlirType t = mlirMemRefTypeContiguousGetChecked( - elementType, shape.size(), shape.data(), memorySpace, loc); +std::vector layout, unsigned memorySpace, +DefaultingPyLocation loc) { + SmallVector maps; + maps.reserve(layout.size()); + for (PyAffineMap &map : layout) + maps.push_back(map); + + MlirType t = mlirMemRefTypeGetChecked(elementType, shape.size(), + shape.data(), maps.size(), + maps.data(), memorySpace, loc); // TODO: Rework error reporting once diagnostic engine is exposed // in C API. if (mlirTypeIsNull(t)) { @@ -2565,15 +2573,11 @@ class PyMemRefType : public PyConcreteType { } return PyMemRefType(elementType.getContext(), t); }, - py::arg("element_type"), py::arg("shape"), py::arg("memory_space"), + py::arg("element_type"), py::arg("shape"), + py::arg("layout") = py::list(), py::arg("memory_space") = 0, py::arg("loc") = py::none(), "Create a memref type") -.def_property_readonly( -"num_affine_maps", -[](PyMemRefType &self) -> intptr_t { - return mlirMemRefTypeGetNumAffineMaps(self); -}, -"Returns the number of affine layout maps in the given MemRef " -"type.") +.def_property_readonly("layout", &PyMemRefType::getLayout, + "The list of layout maps of the MemRef type.")
[llvm-branch-commits] [mlir] 20d0cbd - [mlir] Tighten type verifiers for LLVM dialect ops results
Author: Alex Zinenko Date: 2020-12-15T23:50:02+01:00 New Revision: 20d0cbd3fadf5a6e78373ab5c9d35e9e5d49f172 URL: https://github.com/llvm/llvm-project/commit/20d0cbd3fadf5a6e78373ab5c9d35e9e5d49f172 DIFF: https://github.com/llvm/llvm-project/commit/20d0cbd3fadf5a6e78373ab5c9d35e9e5d49f172.diff LOG: [mlir] Tighten type verifiers for LLVM dialect ops results Now that we have predicates for LLVM dialect types in ODS, we can use them to restrict the types allowed in results of LLVM dialect operations. This also serves as additional documentation for these operations. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D93329 Added: Modified: mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp mlir/test/Dialect/LLVMIR/invalid.mlir Removed: diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 807ea8826ef8..da25c0d3f92d 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -94,9 +94,8 @@ class LLVM_ArithmeticOpBase { let arguments = (ins LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); - let parser = - [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }]; - let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }]; + let results = (outs LLVM_ScalarOrVectorOf:$res); + let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($res)"; } class LLVM_IntArithmeticOp traits = []> : @@ -112,9 +111,8 @@ class LLVM_UnaryArithmeticOp, LLVM_Builder<"$res = builder." # builderFunc # "($operand);"> { let arguments = (ins type:$operand); - let parser = - [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }]; - let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }]; + let results = (outs type:$res); + let assemblyFormat = "$operand attr-dict `:` type($res)"; } // Integer binary operations. @@ -157,6 +155,7 @@ def LLVM_ICmpOp : LLVM_OneResultOp<"icmp", [NoSideEffect]> { let arguments = (ins ICmpPredicate:$predicate, LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); + let results = (outs LLVM_ScalarOrVectorOf:$res); let llvmBuilder = [{ $res = builder.CreateICmp(getLLVMCmpPredicate($predicate), $lhs, $rhs); }]; @@ -204,6 +203,7 @@ def LLVM_FCmpOp : LLVM_OneResultOp<"fcmp", [NoSideEffect]> { let arguments = (ins FCmpPredicate:$predicate, LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); + let results = (outs LLVM_ScalarOrVectorOf:$res); let llvmBuilder = [{ $res = builder.CreateFCmp(getLLVMCmpPredicate($predicate), $lhs, $rhs); }]; @@ -257,6 +257,7 @@ def LLVM_AllocaOp : LLVM_OneResultOp<"alloca"> { let arguments = (ins LLVM_AnyInteger:$arraySize, OptionalAttr:$alignment); + let results = (outs LLVM_AnyPointer:$res); string llvmBuilder = [{ auto *inst = builder.CreateAlloca( $_resultType->getPointerElementType(), $arraySize); @@ -280,6 +281,7 @@ def LLVM_GEPOp : LLVM_OneResultOp<"getelementptr", [NoSideEffect]>, LLVM_Builder<"$res = builder.CreateGEP($base, $indices);"> { let arguments = (ins LLVM_ScalarOrVectorOf:$base, Variadic>:$indices); + let results = (outs LLVM_ScalarOrVectorOf:$res); let assemblyFormat = [{ $base `[` $indices `]` attr-dict `:` functional-type(operands, results) }]; @@ -291,6 +293,7 @@ def LLVM_LoadOp : let arguments = (ins LLVM_PointerTo:$addr, OptionalAttr:$alignment, UnitAttr:$volatile_, UnitAttr:$nontemporal); + let results = (outs LLVM_Type:$res); string llvmBuilder = [{ auto *inst = builder.CreateLoad($addr, $volatile_); }] # setAlignmentCode # setNonTemporalMetadataCode # [{ @@ -330,52 +333,64 @@ def LLVM_StoreOp : // Casts. class LLVM_CastOp traits = []> : + Type resultType, list traits = []> : LLVM_OneResultOp, LLVM_Builder<"$res = builder." # builderFunc # "($arg, $_resultType);"> { let arguments = (ins type:$arg); + let results = (outs resultType:$res); let parser = [{ return mlir::impl::parseCastOp(parser, result); }]; let printer = [{ mlir::impl::printCastOp(this->getOperation(), p); }]; } def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "CreateBitCast", - LLVM_AnyNonAggregate>; + LLVM_AnyNonAggregate, LLVM_AnyNonAggregate>; def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "CreateAddrSpaceCast", + LLVM_ScalarOrVectorOf, LLVM_ScalarOrVectorOf>; def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "CreateIntToPtr", -
[llvm-branch-commits] [mlir] 02220f3 - [mlir] NFC: retire LLVM_Zero/OneResultOp from LLVM dialect ODS
Author: Alex Zinenko Date: 2020-12-15T23:50:03+01:00 New Revision: 02220f3204980496c8877abb51ba1fd87a108541 URL: https://github.com/llvm/llvm-project/commit/02220f3204980496c8877abb51ba1fd87a108541 DIFF: https://github.com/llvm/llvm-project/commit/02220f3204980496c8877abb51ba1fd87a108541.diff LOG: [mlir] NFC: retire LLVM_Zero/OneResultOp from LLVM dialect ODS These classes were initially introduced to factor out two common parts of LLVM op definitions: the fact that they have no results or a single result of LLVM_Type, and the default builders. Neither of the two parts is really common anymore: many ops have more specific on the result type, and many ops provide custom builders. The TableGen classes only add conceptual complexity and make LLVM dialect definition dissimilar to other dialects. Remove them in favor of explicitly specified builders (results are already specified). Depends On D93329 Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D93330 Added: Modified: mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td Removed: diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index da25c0d3f92d..59ea92d88330 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -43,16 +43,6 @@ def LLVM_ZeroResultOpBuilder : } }]>; -class LLVM_TwoBuilders { - list builders = [b1, b2]; -} - -// Base class for LLVM operations with one result. -class LLVM_OneResultOp traits = []> : -LLVM_Op, Results<(outs LLVM_Type:$res)> { - let builders = [LLVM_OneResultOpBuilder]; -} - // Compatibility builder that takes an instance of wrapped llvm::VoidType // to indicate no result. def LLVM_VoidResultTypeOpBuilder : @@ -66,10 +56,6 @@ def LLVM_VoidResultTypeOpBuilder : build($_builder, $_state, operands, attributes); }]>; -// Base class for LLVM operations with zero results. -class LLVM_ZeroResultOp traits = []> : -LLVM_Op, Results<(outs)>, -LLVM_TwoBuilders; // Opaque builder used for terminator operations that contain successors. def LLVM_TerminatorPassthroughOpBuilder : @@ -89,12 +75,13 @@ class LLVM_TerminatorOp traits = []> : // Class for arithmetic binary operations. class LLVM_ArithmeticOpBase traits = []> : -LLVM_OneResultOp, LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> { let arguments = (ins LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); let results = (outs LLVM_ScalarOrVectorOf:$res); + let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($res)"; } class LLVM_IntArithmeticOp traits = []> : -LLVM_OneResultOp, LLVM_Builder<"$res = builder." # builderFunc # "($operand);"> { let arguments = (ins type:$operand); let results = (outs type:$res); + let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = "$operand attr-dict `:` type($res)"; } @@ -151,7 +139,7 @@ def ICmpPredicate : I64EnumAttr< } // Other integer operations. -def LLVM_ICmpOp : LLVM_OneResultOp<"icmp", [NoSideEffect]> { +def LLVM_ICmpOp : LLVM_Op<"icmp", [NoSideEffect]> { let arguments = (ins ICmpPredicate:$predicate, LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); @@ -199,7 +187,7 @@ def FCmpPredicate : I64EnumAttr< } // Other integer operations. -def LLVM_FCmpOp : LLVM_OneResultOp<"fcmp", [NoSideEffect]> { +def LLVM_FCmpOp : LLVM_Op<"fcmp", [NoSideEffect]> { let arguments = (ins FCmpPredicate:$predicate, LLVM_ScalarOrVectorOf:$lhs, LLVM_ScalarOrVectorOf:$rhs); @@ -252,9 +240,7 @@ class MemoryOpWithAlignmentAndAttributes : MemoryOpWithAlignmentBase { } // Memory-related operations. -def LLVM_AllocaOp : -MemoryOpWithAlignmentBase, -LLVM_OneResultOp<"alloca"> { +def LLVM_AllocaOp : LLVM_Op<"alloca">, MemoryOpWithAlignmentBase { let arguments = (ins LLVM_AnyInteger:$arraySize, OptionalAttr:$alignment); let results = (outs LLVM_AnyPointer:$res); @@ -277,19 +263,18 @@ def LLVM_AllocaOp : let printer = [{ printAllocaOp(p, *this); }]; } -def LLVM_GEPOp : LLVM_OneResultOp<"getelementptr", [NoSideEffect]>, +def LLVM_GEPOp : LLVM_Op<"getelementptr", [NoSideEffect]>, LLVM_Builder<"$res = builder.CreateGEP($base, $indices);"> { let arguments = (ins LLVM_ScalarOrVectorOf:$base, Variadic>:$indices); let results = (outs LLVM_ScalarOrVectorOf:$res); + let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = [{ $base `[` $indices `]` attr-dict `:` functional-type(operands, results) }]; } -def LLVM_LoadOp : -MemoryOpWithAlignmentAndAttributes, -LLVM_OneResultOp<"load"> { +def LLVM_LoadOp : LLVM_Op<"load">, MemoryOpWithAlignmentAndAttributes { let arguments
[llvm-branch-commits] [mlir] 96076a2 - [mlir] Support index and memref types in llvm.mlir.cast
Author: Alex Zinenko Date: 2020-12-17T09:21:42+01:00 New Revision: 96076a2edbd63e3e9d6ee0eca0c90d34579b7602 URL: https://github.com/llvm/llvm-project/commit/96076a2edbd63e3e9d6ee0eca0c90d34579b7602 DIFF: https://github.com/llvm/llvm-project/commit/96076a2edbd63e3e9d6ee0eca0c90d34579b7602.diff LOG: [mlir] Support index and memref types in llvm.mlir.cast This operation is designed to support partial conversion, more specifically the IR state in which some operations expect or produce built-in types and some operations produce and expect LLVM dialect types. It is reasonable for it to support cast between built-in types and any equivalent that could be produced by the type conversion. (At the same time, we don't want the dialect to depend on the type conversion as it could lead to a dependency cycle). Introduce support for casting from index to any integer type and back, and from memref to bare pointer or memref descriptor type and back. Contrary to what the TODO in the code stated, there are no particular precautions necessary to handle the bare pointer conversion for memerfs. This conversion applies exclusively to statically-shaped memrefs, so we can always recover the full descriptor contents from the type. This patch simultaneously tightens the verification for other types to only accept matching pairs of types, e.g., i64 and !llvm.i64, as opposed to the previous implementation that only checked if the types were generally allowed byt not for matching, e.g. i64 could be "casted" to !llvm.bfloat, which is not the intended semantics. Move the relevant test under test/Dialect/LLVMIR because it is not specific to the conversion pass, but rather exercises an op in the dialect. If we decide this op does not belong to the LLVM dialect, both the dialect and the op should move together. Reviewed By: silvas, ezhulenev Differential Revision: https://reviews.llvm.org/D93405 Added: mlir/test/Dialect/LLVMIR/dialect-cast.mlir Modified: mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp mlir/test/Conversion/StandardToLLVM/invalid.mlir Removed: diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index e3a5de788e49..d70a327824b7 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1067,40 +1067,190 @@ static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { // Verifier for LLVM::DialectCastOp. //===--===// -static LogicalResult verify(DialectCastOp op) { - auto verifyMLIRCastType = [&op](Type type) -> LogicalResult { -if (auto llvmType = type.dyn_cast()) { - if (llvmType.isVectorTy()) -llvmType = llvmType.getVectorElementType(); - if (llvmType.isIntegerTy() || llvmType.isBFloatTy() || - llvmType.isHalfTy() || llvmType.isFloatTy() || - llvmType.isDoubleTy()) { -return success(); - } - return op.emitOpError("type must be non-index integer types, float " -"types, or vector of mentioned types."); +/// Checks if `llvmType` is dialect cast-compatible with `index` type. Does not +/// report the error, the user is expected to produce an appropriate message. +// TODO: make the size depend on data layout rather than on the conversion +// pass option, and pull that information here. +static LogicalResult verifyCastWithIndex(LLVMType llvmType) { + return success(llvmType.isa()); +} + +/// Checks if `llvmType` is dialect cast-compatible with built-in `type` and +/// reports errors to the location of `op`. +static LogicalResult verifyCast(DialectCastOp op, LLVMType llvmType, +Type type) { + // Index is compatible with any integer. + if (type.isIndex()) { +if (succeeded(verifyCastWithIndex(llvmType))) + return success(); + +return op.emitOpError("invalid cast between index and non-integer type"); + } + + // Simple one-to-one mappings for floating point types. + if (type.isF16()) { +if (llvmType.isa()) + return success(); +return op.emitOpError( +"invalid cast between f16 and a type other than !llvm.half"); + } + if (type.isBF16()) { +if (llvmType.isa()) + return success(); +return op->emitOpError( +"invalid cast between bf16 and a type other than !llvm.bfloat"); + } + if (type.isF32()) { +if (llvmType.isa()) + return success(); +return op->emitOpError( +"invalid cast between f32 and a type other than !llvm.float"); + } + if (type.isF64()) { +if (llvmType.isa()) + return success(); +return op->emitOpError( +"invalid cast between f64 and a type other than !llvm.double"); + } + + // Singless integers are compatible with LLVM integer of the same bitwidth. + if (type.isSignlessInteger()) { +auto llvmInt = llvmType.dyn_cast(); +
[llvm-branch-commits] [mlir] c275125 - [mlir] partially update LLVM dialect documentation
Author: Alex Zinenko Date: 2020-12-17T12:32:34+01:00 New Revision: c2751250f33f61e95e5d9feec95e5b063c601806 URL: https://github.com/llvm/llvm-project/commit/c2751250f33f61e95e5d9feec95e5b063c601806 DIFF: https://github.com/llvm/llvm-project/commit/c2751250f33f61e95e5d9feec95e5b063c601806.diff LOG: [mlir] partially update LLVM dialect documentation Rewrite the parts of the documentation that became stale: context/module handling and type system. Expand the type system description. Reviewed By: nicolasvasilache Differential Revision: https://reviews.llvm.org/D93315 Added: Modified: mlir/docs/Dialects/LLVM.md Removed: diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md index 9e2dbd65b4a3..c4607dbd735b 100644 --- a/mlir/docs/Dialects/LLVM.md +++ b/mlir/docs/Dialects/LLVM.md @@ -1,49 +1,296 @@ # 'llvm' Dialect -This dialect wraps the LLVM IR types and instructions into MLIR types and -operations. It provides several additional operations that are necessary to -cover for the diff erences in the IR structure (e.g., MLIR does not have `phi` -operations and LLVM IR does not have a `constant` operation). +This dialect maps [LLVM IR](https://llvm.org/docs/LangRef.html) into MLIR by +defining the corresponding operations and types. LLVM IR metadata is usually +represented as MLIR attributes, which offer additional structure verification. -In this document, we use "LLVM IR" to designate the +We use "LLVM IR" to designate the [intermediate representation of LLVM](https://llvm.org/docs/LangRef.html) and -"LLVM IR _dialect_" to refer to the MLIR dialect reflecting LLVM instructions -and types. +"LLVM _dialect_" or "LLVM IR _dialect_" to refer to this MLIR dialect. + +Unless explicitly stated otherwise, the semantics of the LLVM dialect operations +must correspond to the semantics of LLVM IR instructions and any divergence is +considered a bug. The dialect also contains auxiliary operations that smoothen +the diff erences in the IR structure, e.g., MLIR does not have `phi` operations +and LLVM IR does not have a `constant` operation. These auxiliary operations are +systematically prefixed with `mlir`, e.g. `llvm.mlir.constant` where `llvm.` is +the dialect namespace prefix. [TOC] -## Context and Module Association +## Dependency on LLVM IR + +LLVM dialect is not expected to depend on any object that requires an +`LLVMContext`, such as an LLVM IR instruction or type. Instead, MLIR provides +thread-safe alternatives compatible with the rest of the infrastructure. The +dialect is allowed to depend on the LLVM IR objects that don't require a +context, such as data layout and triple description. + +## Module Structure + +IR modules use the built-in MLIR `ModuleOp` and support all its features. In +particular, modules can be named, nested and are subject to symbol visibility. +Modules can contain any operations, including LLVM functions and globals. -The LLVM IR dialect object _contains_ an LLVM Context and an LLVM Module that it -uses to define, print, parse and manage LLVM IR types. These objects can be -obtained from the dialect object using `.getLLVMContext()` and -`getLLVMModule()`. All LLVM IR objects that interact with the LLVM IR dialect -must exist in the dialect's context. +### Data Layout and Triple + +An IR module may have an optional data layout and triple information attached +using MLIR attributes `llvm.data_layout` and `llvm.triple`, respectively. Both +are string attributes with the +[same syntax](https://llvm.org/docs/LangRef.html#data-layout) as in LLVM IR and +are verified to be correct. They can be defined as follows. + +```mlir +module attributes {llvm.data_layout = "e", + llvm.target_triple = "aarch64-linux-android"} { + // module contents +} +``` ## Types -The LLVM IR dialect defines a single MLIR type, `LLVM::LLVMType`, that can wrap -any existing LLVM IR type. Its syntax is as follows +LLVM dialect defines a set of types that correspond to LLVM IR types. The +dialect type system is _closed_: types from other dialects are not allowed +within LLVM dialect aggregate types. This property allows for more concise +custom syntax and ensures easy translation to LLVM IR. + +Similarly to other MLIR context-owned objects, the creation and manipulation of +LLVM dialect types is thread-safe. + +MLIR does not support module-scoped named type declarations, e.g. `%s = type +{i32, i32}` in LLVM IR. Instead, types must be fully specified at each use, +except for recursive types where only the first reference to a named type needs +to be fully specified. MLIR type aliases are supported for top-level types, i.e. +they cannot be used inside the type due to type system closedness. + +The general syntax of LLVM dialect types is `!llvm.`, followed by a type kind +identifier (e.g., `ptr` for pointer or `struct` for structure) and by an +optional list of type
[llvm-branch-commits] [mlir] ccdd8c7 - [mlir] Move LLVM Dialect Op documentation to ODS
Author: Alex Zinenko Date: 2020-12-17T12:32:35+01:00 New Revision: ccdd8c7759459ef4b9b09820d241081d387be779 URL: https://github.com/llvm/llvm-project/commit/ccdd8c7759459ef4b9b09820d241081d387be779 DIFF: https://github.com/llvm/llvm-project/commit/ccdd8c7759459ef4b9b09820d241081d387be779.diff LOG: [mlir] Move LLVM Dialect Op documentation to ODS This was long overdue. The initial documentation for the LLVM dialect was introduced before ODS had support for long descriptions. This is now possible, so the documentation is moved to ODS, which can serve as a single source of truth. The high-level description of the dialect structure is updated to reflect that. Depends On: D93315 Reviewed By: rriddle, mehdi_amini Differential Revision: https://reviews.llvm.org/D93425 Added: Modified: mlir/docs/Dialects/LLVM.md mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td Removed: diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md index c4607dbd735b..fbe1a1cfe7ea 100644 --- a/mlir/docs/Dialects/LLVM.md +++ b/mlir/docs/Dialects/LLVM.md @@ -47,6 +47,143 @@ module attributes {llvm.data_layout = "e", } ``` +### Functions + +LLVM functions are represented by a special operation, `llvm.func`, that has +syntax similar to that of the built-in function operation but supports +LLVM-related features such as linkage and variadic argument lists. See detailed +description in the operation list [below](#llvmfunc-mlirllvmllvmfuncop). + +### PHI Nodes and Block Arguments + +MLIR uses block arguments instead of PHI nodes to communicate values between +blocks. Therefore, the LLVM dialect has no operation directly equivalent to +`phi` in LLVM IR. Instead, all terminators can pass values as successor operands +as these values will be forwarded as block arguments when the control flow is +transferred. + +For example: + +```mlir +^bb1: + %0 = llvm.addi %arg0, %cst : !llvm.i32 + llvm.br ^bb2[%0: !llvm.i32] + +// If the control flow comes from ^bb1, %arg1 == %0. +^bb2(%arg1: !llvm.i32) + // ... +``` + +is equivalent to LLVM IR + +```llvm +%0: + %1 = add i32 %arg0, %cst + br %3 + +%3: + %arg1 = phi [%1, %0], //... +``` + +Since there is no need to use the block identifier to diff erentiate the source +of diff erent values, the LLVM dialect supports terminators that transfer the +control flow to the same block with diff erent arguments. For example: + +```mlir +^bb1: + llvm.cond_br %cond, ^bb2[%0: !llvm.i32], ^bb2[%1: !llvm.i32] + +^bb2(%arg0: !llvm.i32): + // ... +``` + +### Context-Level Values + +Some value kinds in LLVM IR, such as constants and undefs, are uniqued in +context and used directly in relevant operations. MLIR does not support such +values for thread-safety and concept parsimony reasons. Instead, regular values +are produced by dedicated operations that have the corresponding semantics: +[`llvm.mlir.constant`](#llvmmlirconstant-mlirllvmconstantop), +[`llvm.mlir.undef`](#llvmmlirundef-mlirllvmundefop), +[`llvm.mlir.null`](#llvmmlirnull-mlirnullop). Note how these operations are +prefixed with `mlir.` to indicate that they don't belong to LLVM IR but are only +necessary to model it in MLIR. The values produced by these operations are +usable just like any other value. + +Examples: + +```mlir +// Create an undefined value of structure type with a 32-bit integer followed +// by a float. +%0 = llvm.mlir.undef : !llvm.struct<(i32, float)> + +// Null pointer to i8. +%1 = llvm.mlir.null : !llvm.ptr + +// Null pointer to a function with signature void(). +%2 = llvm.mlir.null : !llvm.ptr> + +// Constant 42 as i32. +%3 = llvm.mlir.constant(42 : i32) : !llvm.i32 + +// Splat dense vector constant. +%3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : !llvm.vec<4 x float> +``` + +Note that constants use built-in types within the initializer definition: MLIR +attributes are typed and the attributes used for constants require a built-in +type. + +### Globals + +Global variables are also defined using a special operation, +[`llvm.mlir.global`](#llvmmlirglobal-mlirllvmglobalop), located at the module +level. Globals are MLIR symbols and are identified by their name. + +Since functions need to be isolated-from-above, i.e. values defined outside the +function cannot be directly used inside the function, an additional operation, +[`llvm.mlir.addressof`](#llvmmliraddressof-mlirllvmaddressofop), is provided to +locally define a value containing the _address_ of a global. The actual value +can then be loaded from that pointer, or a new value can be stored into it if +the global is not declared constant. This is similar to LLVM IR where globals +are accessed through name and have a pointer type. + +### Linkage + +Module-level named objects in the LLVM dialect, namely functions and globals, +have an optional _linkage_ attribute derived from LLVM IR +[linkage types]
[llvm-branch-commits] [mlir] eb4917d - [mlir] Fix syntax error in markdown documentation
Author: Alex Zinenko Date: 2020-12-17T14:09:31+01:00 New Revision: eb4917d121e21aaf8406efe3d5e4f1f06cb7c238 URL: https://github.com/llvm/llvm-project/commit/eb4917d121e21aaf8406efe3d5e4f1f06cb7c238 DIFF: https://github.com/llvm/llvm-project/commit/eb4917d121e21aaf8406efe3d5e4f1f06cb7c238.diff LOG: [mlir] Fix syntax error in markdown documentation Added: Modified: mlir/docs/Dialects/LLVM.md Removed: diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md index fbe1a1cfe7ea..3b9150f0e69d 100644 --- a/mlir/docs/Dialects/LLVM.md +++ b/mlir/docs/Dialects/LLVM.md @@ -434,4 +434,4 @@ MLIR, blocks are not values and don't need a type. All operations in the LLVM IR dialect have a custom form in MLIR. The mnemonic of an operation is that used in LLVM IR prefixed with "`llvm.`". -[include "Dialects/LLVMOps.md" +[include "Dialects/LLVMOps.md"] ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] 0efb0dd - [mlir] Partially update the conversion-to-llvm document
Author: Alex Zinenko Date: 2020-12-17T22:00:09+01:00 New Revision: 0efb0dd978014c9ca5ef4cd93516a0cd6e77f185 URL: https://github.com/llvm/llvm-project/commit/0efb0dd978014c9ca5ef4cd93516a0cd6e77f185 DIFF: https://github.com/llvm/llvm-project/commit/0efb0dd978014c9ca5ef4cd93516a0cd6e77f185.diff LOG: [mlir] Partially update the conversion-to-llvm document This document was not updated after the LLVM dialect type system had been reimplemented and was using an outdated syntax. Rewrite the part of the document that concerns type conversion and prepare the ground for splitting it into a document that explains how built-in types are converted and a separate document that explains how standard types and functions are converted, which will better correspond to the fact that built-in types do not belong to the standard dialect. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D93486 Added: Modified: mlir/docs/ConversionToLLVMDialect.md Removed: diff --git a/mlir/docs/ConversionToLLVMDialect.md b/mlir/docs/ConversionToLLVMDialect.md index 27b732015f9f..778eea6184c9 100644 --- a/mlir/docs/ConversionToLLVMDialect.md +++ b/mlir/docs/ConversionToLLVMDialect.md @@ -1,16 +1,19 @@ # Conversion to the LLVM Dialect -Conversion from the Standard to the [LLVM Dialect](Dialects/LLVM.md) can be -performed by the specialized dialect conversion pass by running: +Conversion from several dialects that rely on +[built-in types](LangRef.md#builtin-types) to the +[LLVM Dialect](Dialects/LLVM.md) is expected to be performed through the +[Dialect Conversion](DialectConversion.md) infrastructure. -```shell -mlir-opt -convert-std-to-llvm -``` +The conversion of types and that of the overall module structure is described in +this document. Individual conversion passes provide a set of conversion patterns +for ops in diff erent dialects, such as `-convert-std-to-llvm` for ops in the +[Standard dialect](Dialects/Standard.md) and `-convert-vector-to-llvm` in the +[Vector dialect](Dialects/Vector.md). *Note that some conversions subsume the +others.* -It performs type and operation conversions for a subset of operations from -standard dialect (operations on scalars and vectors, control flow operations) as -described in this document. We use the terminology defined by the -[LLVM IR Dialect description](Dialects/LLVM.md) throughout this document. +We use the terminology defined by the +[LLVM Dialect description](Dialects/LLVM.md) throughout this document. [TOC] @@ -22,19 +25,19 @@ Scalar types are converted to their LLVM counterparts if they exist. The following conversions are currently implemented: - `i*` converts to `!llvm.i*` +- `bf16` converts to `!llvm.bfloat` - `f16` converts to `!llvm.half` - `f32` converts to `!llvm.float` - `f64` converts to `!llvm.double` -Note: `bf16` type is not supported by LLVM IR and cannot be converted. - ### Index Type -Index type is converted to a wrapped LLVM IR integer with bitwidth equal to the -bitwidth of the pointer size as specified by the -[data layout](https://llvm.org/docs/LangRef.html#data-layout) of the LLVM module -[contained](Dialects/LLVM.md#context-and-module-association) in the LLVM Dialect -object. For example, on x86-64 CPUs it converts to `!llvm.i64`. +Index type is converted to an LLVM dialect integer type with bitwidth equal to +the bitwidth of the pointer size as specified by the +[data layout](Dialects/LLVM.md#data-layout-and-triple) of the closest module. +For example, on x86-64 CPUs it converts to `!llvm.i64`. This behavior can be +overridden by the type converter configuration, which is often exposed as a pass +option by conversion passes. ### Vector Types @@ -45,31 +48,54 @@ size with element type converted using these conversion rules. In the n-dimensional case, MLIR vectors are converted to (n-1)-dimensional array types of one-dimensional vectors. -For example, `vector<4 x f32>` converts to `!llvm<"<4 x float>">` and `vector<4 -x 8 x 16 x f32>` converts to `!llvm<"[4 x [8 x <16 x float>]]">`. +For example, `vector<4 x f32>` converts to `!llvm.vec<4 x float>` and `vector<4 +x 8 x 16 x f32>` converts to `!llvm.array<4 x array<8 x vec<16 x float>>>`. -### Memref Types +### Ranked Memref Types Memref types in MLIR have both static and dynamic information associated with -them. The dynamic information comprises the buffer pointer as well as sizes and +them. In the general case, the dynamic information describes dynamic sizes in +the logical indexing space and any symbols bound to the memref. This dynamic +information must be present at runtime in the LLVM dialect equivalent type. + +In practice, the conversion supports two conventions: + +- the default convention for memrefs in the +**[strided form](LangRef.md#strided-memref)**; +- a "bare pointer" conversion for statically-shaped memrefs with
[llvm-branch-commits] [mlir] 2f5569f - [mlir] remove deprecated string-based OpBuilder from ODS
Author: Alex Zinenko Date: 2020-12-22T09:57:49+01:00 New Revision: 2f5569f6f67a30f7774f7c2d2f3d726752a862ae URL: https://github.com/llvm/llvm-project/commit/2f5569f6f67a30f7774f7c2d2f3d726752a862ae DIFF: https://github.com/llvm/llvm-project/commit/2f5569f6f67a30f7774f7c2d2f3d726752a862ae.diff LOG: [mlir] remove deprecated string-based OpBuilder from ODS It has been deprecated with a warning for two months, removing. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D93623 Added: Modified: mlir/include/mlir/IR/OpBase.td mlir/test/mlir-tblgen/op-decl.td mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp Removed: diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td index 0f060b2b1a0a..0ae572c38f49 100644 --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -1939,15 +1939,6 @@ def region; // Marker used to identify the successor list for an op. def successor; -// Base class for custom builders. This is a transient class that will go away -// when the transition to the DAG form of builder declaration is complete. -// Should not be used directly. -class OpBuilderBase { - string params = ?; - dag dagParams = dp; - code body = b; -} - // Class for defining a custom builder. // // TableGen generates several generic builders for each op by default (see @@ -1986,11 +1977,9 @@ class OpBuilderBase { // If an empty string is passed in for `body`, then *only* the builder // declaration will be generated; this provides a way to define complicated // builders entirely in C++. -class OpBuilderDAG : OpBuilderBase; - -// Deprecated version of OpBuilder that takes the builder signature as string. -class OpBuilder : OpBuilderBase<(ins), b> { - let params = p; +class OpBuilderDAG { + dag dagParams = p; + code body = b; } // A base decorator class that may optionally be added to OpVariables. @@ -2068,7 +2057,7 @@ class Op props = []> { // ValueRange operands, // ArrayRef attributes); // ``` - list builders = ?; + list builders = ?; // Avoid generating default build functions. Custom builders must be // provided. diff --git a/mlir/test/mlir-tblgen/op-decl.td b/mlir/test/mlir-tblgen/op-decl.td index 29438f1836a7..13daca67c475 100644 --- a/mlir/test/mlir-tblgen/op-decl.td +++ b/mlir/test/mlir-tblgen/op-decl.td @@ -34,8 +34,7 @@ def NS_AOp : NS_Op<"a_op", [IsolatedFromAbove, IsolatedFromAbove]> { VariadicRegion:$someRegions ); let builders = [OpBuilderDAG<(ins "Value":$val)>, - OpBuilderDAG<(ins CArg<"int", "0">:$integer)>, - OpBuilder<"double deprecatedForm">]; + OpBuilderDAG<(ins CArg<"int", "0">:$integer)>]; let parser = [{ foo }]; let printer = [{ bar }]; let verifier = [{ baz }]; @@ -84,7 +83,6 @@ def NS_AOp : NS_Op<"a_op", [IsolatedFromAbove, IsolatedFromAbove]> { // CHECK: ::llvm::Optional< ::llvm::APFloat > attr2(); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, Value val); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, int integer = 0); -// CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, double deprecatedForm); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type r, ::mlir::TypeRange s, ::mlir::Value a, ::mlir::ValueRange b, ::mlir::IntegerAttr attr1, /*optional*/::mlir::FloatAttr attr2, unsigned someRegionsCount) // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type r, ::mlir::TypeRange s, ::mlir::Value a, ::mlir::ValueRange b, uint32_t attr1, /*optional*/::mlir::FloatAttr attr2, unsigned someRegionsCount) // CHECK: static void build(::mlir::OpBuilder &, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::ValueRange operands, ::llvm::ArrayRef<::mlir::NamedAttribute> attributes, unsigned numRegions) diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp index 1c8cbfb9db38..40e1c355daf8 100644 --- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp @@ -1304,8 +1304,7 @@ void OpEmitter::genUseAttrAsResultTypeBuilder() { /// Updates the context `fctx` to enable replacement of $_builder and $_state /// in the body. Reports errors at `loc`. static std::string builderSignatureFromDAG(const DagInit *init, - ArrayRef loc, - FmtContext &fctx) { + ArrayRef loc) { auto *defInit = dyn_cast(init->getOperator()); if (!defInit || !defInit->getDef()->getName().equals("ins")) PrintFatalError(loc
[llvm-branch-commits] [mlir] 8de43b9 - [mlir] Remove instance methods from LLVMType
Author: Alex Zinenko Date: 2020-12-22T23:34:54+01:00 New Revision: 8de43b926f0e960bbc5b6a53d1b613c46b7c774b URL: https://github.com/llvm/llvm-project/commit/8de43b926f0e960bbc5b6a53d1b613c46b7c774b DIFF: https://github.com/llvm/llvm-project/commit/8de43b926f0e960bbc5b6a53d1b613c46b7c774b.diff LOG: [mlir] Remove instance methods from LLVMType LLVMType contains multiple instance methods that were introduced initially for compatibility with LLVM API. These methods boil down to `cast` followed by type-specific call. Arguably, they are mostly used in an LLVM cast-follows-isa anti-pattern. This doesn't connect nicely to the rest of the MLIR infrastructure and actively prevents it from making the LLVM dialect type system more open, e.g., reusing built-in types when appropriate. Remove such instance methods and replaces their uses with apporpriate casts and methods on derived classes. In some cases, the result may look slightly more verbose, but most cases should actually use a stricter subtype of LLVMType anyway and avoid the isa/cast. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D93680 Added: Modified: mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp mlir/lib/Conversion/GPUCommon/ConvertLaunchFuncToRuntimeCalls.cpp mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h mlir/lib/Conversion/GPUToVulkan/ConvertLaunchFuncToVulkanCalls.cpp mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp mlir/lib/Conversion/VectorToROCDL/VectorToROCDL.cpp mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp mlir/lib/ExecutionEngine/JitRunner.cpp mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp mlir/lib/Target/LLVMIR/ModuleTranslation.cpp mlir/test/Dialect/LLVMIR/invalid.mlir Removed: diff --git a/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h b/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h index 7c069c9cd556..63ff16a84ab8 100644 --- a/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h +++ b/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h @@ -446,7 +446,8 @@ class UnrankedMemRefDescriptor : public StructBuilder { /// Builds IR extracting the pointer to the first element of the size array. static Value sizeBasePtr(OpBuilder &builder, Location loc, LLVMTypeConverter &typeConverter, - Value memRefDescPtr, LLVM::LLVMType elemPtrPtrType); + Value memRefDescPtr, + LLVM::LLVMPointerType elemPtrPtrType); /// Builds IR extracting the size[index] from the descriptor. static Value size(OpBuilder &builder, Location loc, LLVMTypeConverter typeConverter, Value sizeBasePtr, diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index df022ef47b33..552fe15e6899 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -51,7 +51,7 @@ def LLVM_VoidResultTypeOpBuilder : [{ auto llvmType = resultType.dyn_cast(); (void)llvmType; assert(llvmType && "result must be an LLVM type"); -assert(llvmType.isVoidTy() && +assert(llvmType.isa() && "for zero-result operands, only 'void' is accepted as result type"); build($_builder, $_state, operands, attributes); }]>; @@ -288,7 +288,7 @@ def LLVM_LoadOp : LLVM_Op<"load">, MemoryOpWithAlignmentAndAttributes { OpBuilderDAG<(ins "Value":$addr, CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile, CArg<"bool", "false">:$isNonTemporal), [{ - auto type = addr.getType().cast().getPointerElementTy(); + auto type = addr.getType().cast().getElementType(); build($_builder, $_state, type, addr, alignment, isVolatile, isNonTemporal); }]>, OpBuilderDAG<(ins "Type":$t, "Value":$addr, @@ -443,8 +443,8 @@ def LLVM_CallOp : LLVM_Op<"call"> { OpBuilderDAG<(ins "LLVMFuncOp":$func, "ValueRange":$operands, CArg<"ArrayRef", "{}">:$attributes), [{ - LLVMType resultType = func.getType().getFunctionResultType(); - if (!resultType.isVoidTy()) + LLVMType resultType = func.getType().getReturnType(); + if (!resultType.isa()) $_state.addTypes(resultType); $_state.addAttribute("callee", $_builder.getSymbolRefAttr(func)); $_state.addAttri
[llvm-branch-commits] [mlir] 65ba0cd - [mlir] Modernize std-to-llvm operation conversion doc
Author: Alex Zinenko Date: 2020-12-23T11:19:58+01:00 New Revision: 65ba0cd3955f8c609ff314dc0cda7bc8ded4a083 URL: https://github.com/llvm/llvm-project/commit/65ba0cd3955f8c609ff314dc0cda7bc8ded4a083 DIFF: https://github.com/llvm/llvm-project/commit/65ba0cd3955f8c609ff314dc0cda7bc8ded4a083.diff LOG: [mlir] Modernize std-to-llvm operation conversion doc This was long overdue. Replace the outdated type syntax with the new syntax, and update the description of how memref load/stores are handled to reflect the latest changes in the implementation. Reviewed By: herhut Differential Revision: https://reviews.llvm.org/D93555 Added: mlir/docs/LLVMDialectMemRefConvention.md Modified: mlir/docs/ConversionToLLVMDialect.md Removed: diff --git a/mlir/docs/ConversionToLLVMDialect.md b/mlir/docs/ConversionToLLVMDialect.md index 778eea6184c9..2b5f98b37686 100644 --- a/mlir/docs/ConversionToLLVMDialect.md +++ b/mlir/docs/ConversionToLLVMDialect.md @@ -280,470 +280,3 @@ Examples: !llvm.func, ptr, i64)>, struct<(ptr, ptr, i64)>)> ()> ``` - -## Calling Convention for Standard Calls - - - -### Result Packing - -In case of multi-result functions, the returned values are inserted into a -structure-typed value before being returned and extracted from it at the call -site. This transformation is a part of the conversion and is transparent to the -defines and uses of the values being returned. - -Example: - -```mlir -func @foo(%arg0: i32, %arg1: i64) -> (i32, i64) { - return %arg0, %arg1 : i32, i64 -} -func @bar() { - %0 = constant 42 : i32 - %1 = constant 17 : i64 - %2:2 = call @foo(%0, %1) : (i32, i64) -> (i32, i64) - "use_i32"(%2#0) : (i32) -> () - "use_i64"(%2#1) : (i64) -> () -} - -// is transformed into - -func @foo(%arg0: !llvm.i32, %arg1: !llvm.i64) -> !llvm<"{i32, i64}"> { - // insert the vales into a structure - %0 = llvm.mlir.undef : !llvm<"{i32, i64}"> - %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{i32, i64}"> - %2 = llvm.insertvalue %arg1, %1[1] : !llvm<"{i32, i64}"> - - // return the structure value - llvm.return %2 : !llvm<"{i32, i64}"> -} -func @bar() { - %0 = llvm.mlir.constant(42 : i32) : !llvm.i32 - %1 = llvm.mlir.constant(17) : !llvm.i64 - - // call and extract the values from the structure - %2 = llvm.call @bar(%0, %1) : (%arg0: !llvm.i32, %arg1: !llvm.i32) -> !llvm<"{i32, i64}"> - %3 = llvm.extractvalue %2[0] : !llvm<"{i32, i64}"> - %4 = llvm.extractvalue %2[1] : !llvm<"{i32, i64}"> - - // use as before - "use_i32"(%3) : (!llvm.i32) -> () - "use_i64"(%4) : (!llvm.i64) -> () -} -``` - -### Calling Convention for Ranked `memref` - -Function _arguments_ of `memref` type, ranked or unranked, are _expanded_ into a -list of arguments of non-aggregate types that the memref descriptor defined -above comprises. That is, the outer struct type and the inner array types are -replaced with individual arguments. - -This convention is implemented in the conversion of `std.func` and `std.call` to -the LLVM dialect, with the former unpacking the descriptor into a set of -individual values and the latter packing those values back into a descriptor so -as to make it transparently usable by other operations. Conversions from other -dialects should take this convention into account. - -This specific convention is motivated by the necessity to specify alignment and -aliasing attributes on the raw pointers underpinning the memref. - -Examples: - -```mlir -func @foo(%arg0: memref) -> () { - "use"(%arg0) : (memref) -> () - return -} - -// Gets converted to the following. - -llvm.func @foo(%arg0: !llvm<"float*">, // Allocated pointer. - %arg1: !llvm<"float*">, // Aligned pointer. - %arg2: !llvm.i64, // Offset. - %arg3: !llvm.i64, // Size in dim 0. - %arg4: !llvm.i64) { // Stride in dim 0. - // Populate memref descriptor structure. - %0 = llvm.mlir.undef : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - %2 = llvm.insertvalue %arg1, %1[1] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - %3 = llvm.insertvalue %arg2, %2[2] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - %4 = llvm.insertvalue %arg3, %3[3, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - %5 = llvm.insertvalue %arg4, %4[4, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - - // Descriptor is now usable as a single value. - "use"(%5) : (!llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">) -> () - llvm.return -} -``` - -```mlir -func @bar() { - %0 = "get"() : () -> (memref) - call @foo(%0) : (memref) -> () - return -} - -// Gets converted to the following. - -llvm.func @bar() { - %0 = "get"() : () -> !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }"> - - // Unpack the me
[llvm-branch-commits] [mlir] 32a884c - [mlir] Add translation of omp.wsloop to LLVM IR
Author: Alex Zinenko Date: 2020-12-23T11:52:28+01:00 New Revision: 32a884c9c52c1216d57835e557233b238d601726 URL: https://github.com/llvm/llvm-project/commit/32a884c9c52c1216d57835e557233b238d601726 DIFF: https://github.com/llvm/llvm-project/commit/32a884c9c52c1216d57835e557233b238d601726.diff LOG: [mlir] Add translation of omp.wsloop to LLVM IR Introduce a translation of OpenMP workshare loop construct to LLVM IR. This is a minimalist version to enable the pipeline and currently only supports static loop schedule (default in the specification) on non-collapsed loops. Other features will be added on per-need basis. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D92055 Added: Modified: mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h mlir/lib/Target/LLVMIR/ModuleTranslation.cpp mlir/test/Target/openmp-llvm.mlir Removed: diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index f915afcf32c9..6c6230f0c2e8 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -185,6 +185,11 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments]> { ]; let regions = (region AnyRegion:$region); + + let extraClassDeclaration = [{ +/// Returns the number of loops in the workshape loop nest. +unsigned getNumLoops() { return lowerBound().size(); } + }]; } def YieldOp : OpenMP_Op<"yield", [NoSideEffect, ReturnLike, Terminator, diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index d3d289414b38..5259ed7fe182 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -100,6 +100,9 @@ class ModuleTranslation { llvm::BasicBlock &continuationIP, llvm::IRBuilder<> &builder, LogicalResult &bodyGenStatus); + virtual LogicalResult convertOmpWsLoop(Operation &opInst, + llvm::IRBuilder<> &builder); + /// Converts the type from MLIR LLVM dialect to LLVM. llvm::Type *convertType(LLVMType type); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index ae0745b0be28..0b2cf7de270f 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -536,6 +536,126 @@ LogicalResult ModuleTranslation::convertOmpMaster(Operation &opInst, return success(); } +/// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder. +LogicalResult ModuleTranslation::convertOmpWsLoop(Operation &opInst, + llvm::IRBuilder<> &builder) { + auto loop = cast(opInst); + // TODO: this should be in the op verifier instead. + if (loop.lowerBound().empty()) +return failure(); + + if (loop.getNumLoops() != 1) +return opInst.emitOpError("collapsed loops not yet supported"); + + if (loop.schedule_val().hasValue() && + omp::symbolizeClauseScheduleKind(loop.schedule_val().getValue()) != + omp::ClauseScheduleKind::Static) +return opInst.emitOpError( +"only static (default) loop schedule is currently supported"); + + llvm::Function *func = builder.GetInsertBlock()->getParent(); + llvm::LLVMContext &llvmContext = llvmModule->getContext(); + + // Find the loop configuration. + llvm::Value *lowerBound = valueMapping.lookup(loop.lowerBound()[0]); + llvm::Value *upperBound = valueMapping.lookup(loop.upperBound()[0]); + llvm::Value *step = valueMapping.lookup(loop.step()[0]); + llvm::Type *ivType = step->getType(); + llvm::Value *chunk = loop.schedule_chunk_var() + ? valueMapping[loop.schedule_chunk_var()] + : llvm::ConstantInt::get(ivType, 1); + + // Set up the source location value for OpenMP runtime. + llvm::DISubprogram *subprogram = + builder.GetInsertBlock()->getParent()->getSubprogram(); + const llvm::DILocation *diLoc = + debugTranslation->translateLoc(opInst.getLoc(), subprogram); + llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder.saveIP(), +llvm::DebugLoc(diLoc)); + + // Generator of the canonical loop body. Produces an SESE region of basic + // blocks. + // TODO: support error propagation in OpenMPIRBuilder and use it instead of + // relying on captured variables. + LogicalResult bodyGenStatus = success(); + auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) { +llvm::IRBuilder<>::InsertPointGuard guard(builder); + +// Make sure further conversions know about the induction variable. +value
[llvm-branch-commits] [mlir] 7ed9cfc - [mlir] Remove static constructors from LLVMType
Author: Alex Zinenko Date: 2020-12-23T13:12:47+01:00 New Revision: 7ed9cfc7b19fdba9eb441ce1a8ba82cda14d76a8 URL: https://github.com/llvm/llvm-project/commit/7ed9cfc7b19fdba9eb441ce1a8ba82cda14d76a8 DIFF: https://github.com/llvm/llvm-project/commit/7ed9cfc7b19fdba9eb441ce1a8ba82cda14d76a8.diff LOG: [mlir] Remove static constructors from LLVMType LLVMType contains numerous static constructors that were initially introduced for API compatibility with LLVM. Most of these merely forward to arguments to `SpecificType::get` (MLIR defines classes for all types, unlike LLVM IR), while some introduce subtle semantics differences due to different modeling of MLIR types (e.g., structs are not auto-renamed in case of conflicts). Furthermore, these constructors don't match MLIR idioms and actively prevent us from making the LLVM dialect type system more open. Remove them and use `SpecificType::get` instead. Depends On D93680 Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D93681 Added: Modified: mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp mlir/lib/Conversion/GPUCommon/ConvertLaunchFuncToRuntimeCalls.cpp mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h mlir/lib/Conversion/GPUCommon/IndexIntrinsicsOpLowering.h mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp mlir/lib/Conversion/GPUToVulkan/ConvertLaunchFuncToVulkanCalls.cpp mlir/lib/Conversion/LinalgToLLVM/LinalgToLLVM.cpp mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp mlir/lib/Conversion/VectorToROCDL/VectorToROCDL.cpp mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp mlir/lib/Target/LLVMIR/ModuleTranslation.cpp mlir/test/lib/Transforms/TestConvertCallOp.cpp Removed: diff --git a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp index a04b3ecd4dae..6fbf29f4128d 100644 --- a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp +++ b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp @@ -111,10 +111,11 @@ class PrintOpLowering : public ConversionPattern { // Create a function declaration for printf, the signature is: // * `i32 (i8*, ...)` -auto llvmI32Ty = LLVM::LLVMType::getInt32Ty(context); -auto llvmI8PtrTy = LLVM::LLVMType::getInt8PtrTy(context); -auto llvmFnType = LLVM::LLVMType::getFunctionTy(llvmI32Ty, llvmI8PtrTy, -/*isVarArg=*/true); +auto llvmI32Ty = LLVM::LLVMIntegerType::get(context, 32); +auto llvmI8PtrTy = +LLVM::LLVMPointerType::get(LLVM::LLVMIntegerType::get(context, 8)); +auto llvmFnType = LLVM::LLVMFunctionType::get(llvmI32Ty, llvmI8PtrTy, + /*isVarArg=*/true); // Insert the printf function into the body of the parent module. PatternRewriter::InsertionGuard insertGuard(rewriter); @@ -133,8 +134,8 @@ class PrintOpLowering : public ConversionPattern { if (!(global = module.lookupSymbol(name))) { OpBuilder::InsertionGuard insertGuard(builder); builder.setInsertionPointToStart(module.getBody()); - auto type = LLVM::LLVMType::getArrayTy( - LLVM::LLVMType::getInt8Ty(builder.getContext()), value.size()); + auto type = LLVM::LLVMArrayType::get( + LLVM::LLVMIntegerType::get(builder.getContext(), 8), value.size()); global = builder.create(loc, type, /*isConstant=*/true, LLVM::Linkage::Internal, name, builder.getStringAttr(value)); @@ -143,11 +144,13 @@ class PrintOpLowering : public ConversionPattern { // Get the pointer to the first character in the global string. Value globalPtr = builder.create(loc, global); Value cst0 = builder.create( -loc, LLVM::LLVMType::getInt64Ty(builder.getContext()), +loc, LLVM::LLVMIntegerType::get(builder.getContext(), 64), builder.getIntegerAttr(builder.getIndexType(), 0)); return builder.create( -loc, LLVM::LLVMType::getInt8PtrTy(builder.getContext()), globalPtr, -ArrayRef({cst0, cst0})); +loc, +LLVM::LLVMPointerType::get( +LLVM::LLVMIntegerType::get(builder.getContext(), 8)), +globalPtr, ArrayRef({cst0, cst0})); } }; } // end anonymous namespace diff --git
[llvm-branch-commits] [mlir] 1ec6086 - [mlir] Avoid cloning ops in SCF parallel conversion to CFG
Author: Alex Zinenko Date: 2020-11-23T14:01:22+01:00 New Revision: 1ec60862d7024118b2db5bcbb280eafcd9193ac5 URL: https://github.com/llvm/llvm-project/commit/1ec60862d7024118b2db5bcbb280eafcd9193ac5 DIFF: https://github.com/llvm/llvm-project/commit/1ec60862d7024118b2db5bcbb280eafcd9193ac5.diff LOG: [mlir] Avoid cloning ops in SCF parallel conversion to CFG The existing implementation of the conversion from SCF Parallel operation to SCF "for" loops in order to further convert those loops to branch-based CFG has been cloning the loop and reduction body operations into the new loop because ConversionPatternRewriter was missing support for moving blocks while replacing their arguments. This functionality now available, use it to implement the conversion and avoid cloning operations, which may lead to doubling of the IR size during the conversion. In addition, this fixes an issue with converting nested SCF "if" conditionals present in "parallel" operations that would cause the conversion infrastructure to stop because of the repeated application of the pattern converting "newly" created "if"s (which were in fact just moved). Arguably, this should be fixed at the infrastructure level and this fix is a workaround. Reviewed By: herhut Differential Revision: https://reviews.llvm.org/D91955 Added: Modified: mlir/lib/Conversion/SCFToStandard/SCFToStandard.cpp mlir/test/Conversion/SCFToStandard/convert-to-cfg.mlir Removed: diff --git a/mlir/lib/Conversion/SCFToStandard/SCFToStandard.cpp b/mlir/lib/Conversion/SCFToStandard/SCFToStandard.cpp index 56f6bf2f05fc..b8f3140dee73 100644 --- a/mlir/lib/Conversion/SCFToStandard/SCFToStandard.cpp +++ b/mlir/lib/Conversion/SCFToStandard/SCFToStandard.cpp @@ -404,7 +404,6 @@ LogicalResult ParallelLowering::matchAndRewrite(ParallelOp parallelOp, PatternRewriter &rewriter) const { Location loc = parallelOp.getLoc(); - BlockAndValueMapping mapping; // For a parallel loop, we essentially need to create an n-dimensional loop // nest. We do this by translating to scf.for ops and have those lowered in @@ -412,6 +411,8 @@ ParallelLowering::matchAndRewrite(ParallelOp parallelOp, // values), forward the initial values for the reductions down the loop // hierarchy and bubble up the results by modifying the "yield" terminator. SmallVector iterArgs = llvm::to_vector<4>(parallelOp.initVals()); + SmallVector ivs; + ivs.reserve(parallelOp.getNumLoops()); bool first = true; SmallVector loopResults(iterArgs); for (auto loop_operands : @@ -420,7 +421,7 @@ ParallelLowering::matchAndRewrite(ParallelOp parallelOp, Value iv, lower, upper, step; std::tie(iv, lower, upper, step) = loop_operands; ForOp forOp = rewriter.create(loc, lower, upper, step, iterArgs); -mapping.map(iv, forOp.getInductionVar()); +ivs.push_back(forOp.getInductionVar()); auto iterRange = forOp.getRegionIterArgs(); iterArgs.assign(iterRange.begin(), iterRange.end()); @@ -439,33 +440,33 @@ ParallelLowering::matchAndRewrite(ParallelOp parallelOp, rewriter.setInsertionPointToStart(forOp.getBody()); } - // Now copy over the contents of the body. + // First, merge reduction blocks into the main region. SmallVector yieldOperands; yieldOperands.reserve(parallelOp.getNumResults()); - for (auto &op : parallelOp.getBody()->without_terminator()) { -// Reduction blocks are handled diff erently. + for (auto &op : *parallelOp.getBody()) { auto reduce = dyn_cast(op); -if (!reduce) { - rewriter.clone(op, mapping); +if (!reduce) continue; -} -// Clone the body of the reduction operation into the body of the loop, -// using operands of "scf.reduce" and iteration arguments corresponding -// to the reduction value to replace arguments of the reduction block. -// Collect operands of "scf.reduce.return" to be returned by a final -// "scf.yield" instead. -Value arg = iterArgs[yieldOperands.size()]; Block &reduceBlock = reduce.reductionOperator().front(); -mapping.map(reduceBlock.getArgument(0), mapping.lookupOrDefault(arg)); -mapping.map(reduceBlock.getArgument(1), -mapping.lookupOrDefault(reduce.operand())); -for (auto &nested : reduceBlock.without_terminator()) - rewriter.clone(nested, mapping); -yieldOperands.push_back( -mapping.lookup(reduceBlock.getTerminator()->getOperand(0))); +Value arg = iterArgs[yieldOperands.size()]; +yieldOperands.push_back(reduceBlock.getTerminator()->getOperand(0)); +rewriter.eraseOp(reduceBlock.getTerminator()); +rewriter.mergeBlockBefore(&reduceBlock, &op, {arg, reduce.operand()}); +rewriter.eraseOp(reduce); } + // Then merge the loop body without the terminator. + rewriter.eraseOp(parallelOp.getBody()->getTerminator()); + Block *newBody = rewriter.getIn
[llvm-branch-commits] [mlir] 31a233d - [mlir] canonicalize away zero-iteration SCF for loops
Author: Alex Zinenko Date: 2020-11-23T15:04:31+01:00 New Revision: 31a233d46367636f94c487b51aa2931a1cc9cf79 URL: https://github.com/llvm/llvm-project/commit/31a233d46367636f94c487b51aa2931a1cc9cf79 DIFF: https://github.com/llvm/llvm-project/commit/31a233d46367636f94c487b51aa2931a1cc9cf79.diff LOG: [mlir] canonicalize away zero-iteration SCF for loops An SCF 'for' loop does not iterate if its lower bound is equal to its upper bound. Remove loops where both bounds are the same SSA value as such bounds are guaranteed to be equal. Similarly, remove 'parallel' loops where at least one pair of respective lower/upper bounds is specified by the same SSA value. Reviewed By: gysit Differential Revision: https://reviews.llvm.org/D91880 Added: Modified: mlir/lib/Dialect/SCF/SCF.cpp mlir/test/Dialect/SCF/canonicalize.mlir Removed: diff --git a/mlir/lib/Dialect/SCF/SCF.cpp b/mlir/lib/Dialect/SCF/SCF.cpp index 5da9f7c29cab..48b1b473f86d 100644 --- a/mlir/lib/Dialect/SCF/SCF.cpp +++ b/mlir/lib/Dialect/SCF/SCF.cpp @@ -521,6 +521,13 @@ struct SimplifyTrivialLoops : public OpRewritePattern { LogicalResult matchAndRewrite(ForOp op, PatternRewriter &rewriter) const override { +// If the upper bound is the same as the lower bound, the loop does not +// iterate, just remove it. +if (op.lowerBound() == op.upperBound()) { + rewriter.replaceOp(op, op.getIterOperands()); + return success(); +} + auto lb = op.lowerBound().getDefiningOp(); auto ub = op.upperBound().getDefiningOp(); if (!lb || !ub) @@ -1066,11 +1073,30 @@ struct CollapseSingleIterationLoops : public OpRewritePattern { return success(); } }; + +/// Removes parallel loops in which at least one lower/upper bound pair consists +/// of the same values - such loops have an empty iteration domain. +struct RemoveEmptyParallelLoops : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(ParallelOp op, +PatternRewriter &rewriter) const override { +for (auto dim : llvm::zip(op.lowerBound(), op.upperBound())) { + if (std::get<0>(dim) == std::get<1>(dim)) { +rewriter.replaceOp(op, op.initVals()); +return success(); + } +} +return failure(); + } +}; + } // namespace void ParallelOp::getCanonicalizationPatterns(OwningRewritePatternList &results, MLIRContext *context) { - results.insert(context); + results.insert( + context); } //===--===// diff --git a/mlir/test/Dialect/SCF/canonicalize.mlir b/mlir/test/Dialect/SCF/canonicalize.mlir index faac86b94cdb..d57563461241 100644 --- a/mlir/test/Dialect/SCF/canonicalize.mlir +++ b/mlir/test/Dialect/SCF/canonicalize.mlir @@ -32,30 +32,6 @@ func @single_iteration(%A: memref) { // - -func @no_iteration(%A: memref) { - %c0 = constant 0 : index - %c1 = constant 1 : index - scf.parallel (%i0, %i1) = (%c0, %c0) to (%c1, %c0) step (%c1, %c1) { -%c42 = constant 42 : i32 -store %c42, %A[%i0, %i1] : memref -scf.yield - } - return -} - -// CHECK-LABEL: func @no_iteration( -// CHECK-SAME:[[ARG0:%.*]]: memref) { -// CHECK: [[C0:%.*]] = constant 0 : index -// CHECK: [[C1:%.*]] = constant 1 : index -// CHECK: [[C42:%.*]] = constant 42 : i32 -// CHECK: scf.parallel ([[V1:%.*]]) = ([[C0]]) to ([[C0]]) step ([[C1]]) { -// CHECK: store [[C42]], [[ARG0]]{{\[}}[[C0]], [[V1]]] : memref -// CHECK: scf.yield -// CHECK: } -// CHECK: return - -// - - func @one_unused(%cond: i1) -> (index) { %c0 = constant 0 : index %c1 = constant 1 : index @@ -241,6 +217,22 @@ func @remove_zero_iteration_loop() { return } +// CHECK-LABEL: @remove_zero_iteration_loop_vals +func @remove_zero_iteration_loop_vals(%arg0: index) { + %c2 = constant 2 : index + // CHECK: %[[INIT:.*]] = "test.init" + %init = "test.init"() : () -> i32 + // CHECK-NOT: scf.for + // CHECK-NOT: test.op + %0 = scf.for %i = %arg0 to %arg0 step %c2 iter_args(%arg = %init) -> (i32) { +%1 = "test.op"(%i, %arg) : (index, i32) -> i32 +scf.yield %1 : i32 + } + // CHECK: "test.consume"(%[[INIT]]) + "test.consume"(%0) : (i32) -> () + return +} + // CHECK-LABEL: @replace_single_iteration_loop func @replace_single_iteration_loop() { // CHECK: %[[LB:.*]] = constant 42 @@ -278,3 +270,24 @@ func @replace_single_iteration_loop_non_unit_step() { "test.consume"(%0) : (i32) -> () return } + +// CHECK-LABEL: @remove_empty_parallel_loop +func @remove_empty_parallel_loop(%lb: index, %ub: index, %s: index) { + // CHECK: %[[INIT:.*]] = "test.init" + %init = "test.init"() : () -> f32 + // CHECK-NOT: s
[llvm-branch-commits] [mlir] f7d033f - [mlir] Support WsLoopOp in OpenMP to LLVM dialect conversion
Author: Alex Zinenko Date: 2020-11-23T23:28:02+01:00 New Revision: f7d033f4d80f476246a70f165e7455639818f907 URL: https://github.com/llvm/llvm-project/commit/f7d033f4d80f476246a70f165e7455639818f907 DIFF: https://github.com/llvm/llvm-project/commit/f7d033f4d80f476246a70f165e7455639818f907.diff LOG: [mlir] Support WsLoopOp in OpenMP to LLVM dialect conversion It is a simple conversion that only requires to change the region argument types, generalize it from ParallelOp. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D91989 Added: Modified: mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir Removed: diff --git a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp index cfb553da407c..91e97ca1ec50 100644 --- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp +++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp @@ -16,18 +16,23 @@ using namespace mlir; namespace { -struct ParallelOpConversion : public ConvertToLLVMPattern { - explicit ParallelOpConversion(MLIRContext *context, -LLVMTypeConverter &typeConverter) - : ConvertToLLVMPattern(omp::ParallelOp::getOperationName(), context, +/// A pattern that converts the region arguments in a single-region OpenMP +/// operation to the LLVM dialect. The body of the region is not modified and is +/// expected to either be processed by the conversion infrastructure or already +/// contain ops compatible with LLVM dialect types. +template +struct RegionOpConversion : public ConvertToLLVMPattern { + explicit RegionOpConversion(MLIRContext *context, + LLVMTypeConverter &typeConverter) + : ConvertToLLVMPattern(OpType::getOperationName(), context, typeConverter) {} LogicalResult matchAndRewrite(Operation *op, ArrayRef operands, ConversionPatternRewriter &rewriter) const override { -auto curOp = cast(op); -auto newOp = rewriter.create(curOp.getLoc(), TypeRange(), - operands, curOp.getAttrs()); +auto curOp = cast(op); +auto newOp = rewriter.create(curOp.getLoc(), TypeRange(), operands, + curOp.getAttrs()); rewriter.inlineRegionBefore(curOp.region(), newOp.region(), newOp.region().end()); if (failed(rewriter.convertRegionTypes(&newOp.region(), typeConverter))) @@ -42,7 +47,8 @@ struct ParallelOpConversion : public ConvertToLLVMPattern { void mlir::populateOpenMPToLLVMConversionPatterns( MLIRContext *context, LLVMTypeConverter &converter, OwningRewritePatternList &patterns) { - patterns.insert(context, converter); + patterns.insert, + RegionOpConversion>(context, converter); } namespace { @@ -63,8 +69,8 @@ void ConvertOpenMPToLLVMPass::runOnOperation() { populateOpenMPToLLVMConversionPatterns(context, converter, patterns); LLVMConversionTarget target(getContext()); - target.addDynamicallyLegalOp( - [&](omp::ParallelOp op) { return converter.isLegal(&op.getRegion()); }); + target.addDynamicallyLegalOp( + [&](Operation *op) { return converter.isLegal(&op->getRegion(0)); }); target.addLegalOp(); if (failed(applyPartialConversion(module, target, std::move(patterns diff --git a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir index d38a6ea7e3a9..62ea39f078b2 100644 --- a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir +++ b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir @@ -28,3 +28,22 @@ func @branch_loop() { } return } + +// CHECK-LABEL: @wsloop +// CHECK: (%[[ARG0:.*]]: !llvm.i64, %[[ARG1:.*]]: !llvm.i64, %[[ARG2:.*]]: !llvm.i64, %[[ARG3:.*]]: !llvm.i64, %[[ARG4:.*]]: !llvm.i64, %[[ARG5:.*]]: !llvm.i64) +func @wsloop(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index, %arg5: index) { + // CHECK: omp.parallel + omp.parallel { +// CHECK: omp.wsloop +// CHECK: (%[[ARG0]], %[[ARG1]], %[[ARG2]], %[[ARG3]], %[[ARG4]], %[[ARG5]]) +"omp.wsloop"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5) ( { +// CHECK: ^{{.*}}(%[[ARG6:.*]]: !llvm.i64, %[[ARG7:.*]]: !llvm.i64): +^bb0(%arg6: index, %arg7: index): // no predecessors + // CHECK: "test.payload"(%[[ARG6]], %[[ARG7]]) : (!llvm.i64, !llvm.i64) -> () + "test.payload"(%arg6, %arg7) : (index, index) -> () + omp.yield +}) {operand_segment_sizes = dense<[2, 2, 2, 0, 0, 0, 0, 0, 0]> : vector<9xi32>} : (index, index, index, index, index, index) -> () +omp.terminator + } + return +} ___ llvm-branch-commits mailing list llvm-branch-commits@lists.
[llvm-branch-commits] [mlir] 63d3198 - [mlir] Fix typos and broken links in LangRef
Author: Felipe de Azevedo Piovezan Date: 2020-11-27T14:07:32+01:00 New Revision: 63d3198cedbca8cf51ce2c73e6c2192cc819d079 URL: https://github.com/llvm/llvm-project/commit/63d3198cedbca8cf51ce2c73e6c2192cc819d079 DIFF: https://github.com/llvm/llvm-project/commit/63d3198cedbca8cf51ce2c73e6c2192cc819d079.diff LOG: [mlir] Fix typos and broken links in LangRef Many pages have had their titles renamed over time, causing broken links to spread throughout the documentation. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D92093 Added: Modified: mlir/docs/LangRef.md mlir/docs/Rationale/Rationale.md Removed: diff --git a/mlir/docs/LangRef.md b/mlir/docs/LangRef.md index 9cd3e657b4d3..82272d1b729f 100644 --- a/mlir/docs/LangRef.md +++ b/mlir/docs/LangRef.md @@ -34,7 +34,7 @@ system](#type-system). [Operations](#operations) are contained in [Blocks](#blocks) and Blocks are contained in [Regions](#regions). Operations are also ordered within their containing block and Blocks are ordered in their containing region, although this order may or may not be semantically -meaningful in a given [kind of region](Interfaces.md#regionkindinterface)). +meaningful in a given [kind of region](Interfaces.md#regionkindinterfaces)). Operations may also contain regions, enabling hierarchical structures to be represented. @@ -55,8 +55,8 @@ allowing operation semantics to be described abstractly using [Traits](Traits.md) and [Interfaces](Interfaces.md), enabling transformations to operate on operations more generically. Traits often describe verification constraints on valid IR, enabling complex invariants to be captured and -checked. (see -[docs/Tutorials/Toy/Ch-2/#op-vs-operation-using-mlir-operations]) +checked. (see [Op vs +Operation](docs/Tutorials/Toy/Ch-2/#op-vs-operation-using-mlir-operations)) One obvious application of MLIR is to represent an [SSA-based](https://en.wikipedia.org/wiki/Static_single_assignment_form) IR, @@ -438,7 +438,7 @@ block-arg-list ::= `(` value-id-and-type-list? `)` A *Block* is an ordered list of operations, concluding with a single [terminator operation](#terminator-operations). In [SSACFG regions](#control-flow-and-ssacfg-regions), each block represents a compiler -[basic block] (https://en.wikipedia.org/wiki/Basic_block) where instructions +[basic block](https://en.wikipedia.org/wiki/Basic_block) where instructions inside the block are executed in order and terminator operations implement control flow branches between basic blocks. @@ -505,7 +505,7 @@ regions: [SSACFG regions](#control-flow-and-ssacfg-regions), which describe control flow between blocks, and [Graph regions](#graph-regions), which do not require control flow between block. The kinds of regions within an operation are described using the -[RegionKindInterface](Interfaces.md#regionkindinterface). +[RegionKindInterface](Interfaces.md#regionkindinterfaces). Regions do not have a name or an address, only the blocks contained in a region do. Regions must be contained within operations and have no type or @@ -561,7 +561,7 @@ defined in a region can never be used outside of the region. ### Control Flow and SSACFG Regions In MLIR, control flow semantics of a region is indicated by -[RegionKind::SSACFG](Interfaces.md#regionkindinterface). Informally, these +[RegionKind::SSACFG](Interfaces.md#regionkindinterfaces). Informally, these regions support semantics where operations in a region 'execute sequentially'. Before an operation executes, its operands have well-defined values. After an operation executes, the operands have the same values and @@ -647,7 +647,7 @@ directly used values remain live. ### Graph Regions In MLIR, graph-like semantics in a region is indicated by -[RegionKind::Graph](Interfaces.md#regionkindinterface). Graph regions are +[RegionKind::Graph](Interfaces.md#regionkindinterfaces). Graph regions are appropriate for concurrent semantics without control flow, or for modeling generic directed graph data structures. Graph regions are appropriate for representing cyclic relationships between coupled values where there is no @@ -869,7 +869,7 @@ function-type ::= type-list-parens `->` function-result-type ``` MLIR supports first-class functions: for example, the -[`constant` operation](Dialects/Standard.md#constant-operation) produces the +[`constant` operation](Dialects/Standard.md#stdconstant-constantop) produces the address of a function as a value. This value may be passed to and returned from functions, merged across control flow boundaries with [block arguments](#blocks), and called with the @@ -888,10 +888,11 @@ index-type ::= `index` ``` The `index` type is a signless integer whose size is equal to the natural -machine word of the target ([rationale](Rationale/Rationale.md#signless-types)) and is -used by the affine constructs in MLIR
[llvm-branch-commits] [mlir] 240dd92 - [OpenMPIRBuilder] forward arguments as pointers to outlined function
Author: Alex Zinenko Date: 2020-12-02T14:59:41+01:00 New Revision: 240dd92432ebbfbf24ef85779f2cdf93e6ddf605 URL: https://github.com/llvm/llvm-project/commit/240dd92432ebbfbf24ef85779f2cdf93e6ddf605 DIFF: https://github.com/llvm/llvm-project/commit/240dd92432ebbfbf24ef85779f2cdf93e6ddf605.diff LOG: [OpenMPIRBuilder] forward arguments as pointers to outlined function OpenMPIRBuilder::createParallel outlines the body region of the parallel construct into a new function that accepts any value previously defined outside the region as a function argument. This function is called back by OpenMP runtime function __kmpc_fork_call, which expects trailing arguments to be pointers. If the region uses a value that is not of a pointer type, e.g. a struct, the produced code would be invalid. In such cases, make createParallel emit IR that stores the value on stack and pass the pointer to the outlined function instead. The outlined function then loads the value back and uses as normal. Reviewed By: jdoerfert, llitchev Differential Revision: https://reviews.llvm.org/D92189 Added: Modified: clang/lib/CodeGen/CGStmtOpenMP.cpp clang/test/OpenMP/parallel_codegen.cpp llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp llvm/lib/Transforms/IPO/OpenMPOpt.cpp llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp mlir/lib/Target/LLVMIR/ModuleTranslation.cpp Removed: diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 2fb4144930df..5e8d98cfe5ef 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1693,7 +1693,7 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { // // TODO: This defaults to shared right now. auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, - llvm::Value &Val, llvm::Value *&ReplVal) { + llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) { // The next line is appropriate only for variables (Val) with the // data-sharing attribute "shared". ReplVal = &Val; diff --git a/clang/test/OpenMP/parallel_codegen.cpp b/clang/test/OpenMP/parallel_codegen.cpp index bceab0637f6a..83561ce6f6a8 100644 --- a/clang/test/OpenMP/parallel_codegen.cpp +++ b/clang/test/OpenMP/parallel_codegen.cpp @@ -133,22 +133,26 @@ int main (int argc, char **argv) { // CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]]) // CHECK-DEBUG-DAG: call void [[OMP_OUTLINED_DEBUG]] +// Note that OpenMPIRBuilder puts the trailing arguments in a diff erent order: +// arguments that are wrapped into additional pointers precede the other +// arguments. This is expected and not problematic because both the call and the +// function are generated from the same place, and the function is internal. // ALL: define linkonce_odr {{[a-z\_\b]*[ ]?i32}} [[TMAIN]](i8** %argc) // ALL: store i8** %argc, i8*** [[ARGC_ADDR:%.+]], // CHECK: call {{.*}}void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[DEF_LOC_2]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i8***, i{{64|32}})* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8*** [[ARGC_ADDR]], i{{64|32}} %{{.+}}) -// IRBUILDER: call {{.*}}void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[DEF_LOC_2]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i8***, i{{64|32}})* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8*** [[ARGC_ADDR]], i{{64|32}} %{{.+}}) +// IRBUILDER: call {{.*}}void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* [[DEF_LOC_2]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i{{64|32}}*, i8***)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i{{64|32}}* %{{.+}}, i8*** [[ARGC_ADDR]]) // ALL: ret i32 0 // ALL-NEXT: } // ALL-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc) // CHECK-DEBUG: store i8** %argc, i8*** [[ARGC_ADDR:%.+]], // CHECK-DEBUG: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @{{.*}}, i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i8***, i64)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8*** [[ARGC_ADDR]], i64 %{{.+}}) -// IRBUILDER-DEBUG: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @{{.*}}, i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i8***, i64)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8*** [[ARGC_ADDR]], i64 %{{.+}}) +// IRBUILDER-DEBUG: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
[llvm-branch-commits] [llvm] c102c78 - [OpenMPIRBuilder] introduce createStaticWorkshareLoop
Author: Alex Zinenko Date: 2020-12-07T22:30:59+01:00 New Revision: c102c783cd08cb1bf9119fe33cce34f6d1563881 URL: https://github.com/llvm/llvm-project/commit/c102c783cd08cb1bf9119fe33cce34f6d1563881 DIFF: https://github.com/llvm/llvm-project/commit/c102c783cd08cb1bf9119fe33cce34f6d1563881.diff LOG: [OpenMPIRBuilder] introduce createStaticWorkshareLoop Introduce a function that creates a statically-scheduled workshare loop out of a canonical loop created earlier by the OpenMPIRBuilder. This basically amounts to injecting runtime calls to the preheader and the after block and updating the trip count. Static scheduling kind is currently hardcoded and needs to be extracted from the runtime library into common TableGen definitions. Differential Revision: https://reviews.llvm.org/D92476 Added: Modified: llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp Removed: diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index a09605bb1023..2e4bb20c7998 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -260,6 +260,32 @@ class OpenMPIRBuilder { Value *Start, Value *Stop, Value *Step, bool IsSigned, bool InclusiveStop); + /// Modifies the canonical loop to be a statically-scheduled workshare loop. + /// + /// This takes a \p LoopInfo representing a canonical loop, such as the one + /// created by \p createCanonicalLoop and emits additional instructions to + /// turn it into a workshare loop. In particular, it calls to an OpenMP + /// runtime function in the preheader to obtain the loop bounds to be used in + /// the current thread, updates the relevant instructions in the canonical + /// loop and calls to an OpenMP runtime finalization function after the loop. + /// + /// \param Loc The source location description, the insertion location + /// is not used. + /// \param CLI A descriptor of the canonical loop to workshare. + /// \param AllocaIP An insertion point for Alloca instructions usable in the + /// preheader of the loop. + /// \param NeedsBarrier Indicates whether a barrier must be insterted after + /// the loop. + /// \param ChunkThe size of loop chunk considered as a unit when + /// scheduling. If \p nullptr, defaults to 1. + /// + /// \returns Updated CanonicalLoopInfo. + CanonicalLoopInfo *createStaticWorkshareLoop(const LocationDescription &Loc, + CanonicalLoopInfo *CLI, + InsertPointTy AllocaIP, + bool NeedsBarrier, + Value *Chunk = nullptr); + /// Generator for '#omp flush' /// /// \param Loc The location where the flush directive was encountered @@ -636,7 +662,9 @@ class OpenMPIRBuilder { /// |Cond---\ /// | | | /// |Body | -/// | | | +/// || || +/// | <...> | +/// || || /// \--Latch | /// | /// Exit @@ -644,7 +672,9 @@ class OpenMPIRBuilder { ///After /// /// Code in the header, condition block, latch and exit block must not have any -/// side-effect. +/// side-effect. The body block is the single entry point into the loop body, +/// which may contain arbitrary control flow as long as all control paths +/// eventually branch to the latch block. /// /// Defined outside OpenMPIRBuilder because one cannot forward-declare nested /// classes. @@ -701,7 +731,7 @@ class CanonicalLoopInfo { /// statements/cancellations). BasicBlock *getAfter() const { return After; } - /// Returns the llvm::Value containing the number of loop iterations. I must + /// Returns the llvm::Value containing the number of loop iterations. It must /// be valid in the preheader and always interpreted as an unsigned integer of /// any bit-width. Value *getTripCount() const { diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 044e69da8665..6587a3637c90 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -999,6 +999,118 @@ CanonicalLoopInfo *OpenMPIRBuilder::createCanonicalLoop( return createCanonicalLoop(Builder.saveIP(), BodyGen, TripCount); } +// Returns an LLVM function to call for initializing loop bounds using OpenMP +// static scheduling depending on `type`. Only i32 and i64 are supported by the +// runtime. Always interpret integers as unsigned similarly to +// CanonicalLoopInfo. +static Fu
[llvm-branch-commits] [mlir] 2fe30a3 - [mlir] properly support min/max in affine parallelization
Author: Alex Zinenko Date: 2020-12-08T10:43:35+01:00 New Revision: 2fe30a3534dad9f982a3d840b4bfa4870b2ba5bc URL: https://github.com/llvm/llvm-project/commit/2fe30a3534dad9f982a3d840b4bfa4870b2ba5bc DIFF: https://github.com/llvm/llvm-project/commit/2fe30a3534dad9f982a3d840b4bfa4870b2ba5bc.diff LOG: [mlir] properly support min/max in affine parallelization The existing implementation of the affine parallelization silently copies over the lower and upper bound maps from affine.for to affine.parallel. However, the semantics of these maps differ between these two ops: in affine.for, a max(min) of results is taken for the lower(upper) bound; in affine.parallel, multiple induction variables can be defined an each result corresponds to one induction variable. Thus the existing implementation could generate invalid IR or IR that passes the verifier but has different semantics than the original code. Fix the parallelization utility to emit dedicated min/max operations before the affine.parallel in such cases. Disallow parallelization if min/max would have been in an operation without the AffineScope trait, e.g., in another loop, since the result of these operations is not considered a valid affine dimension identifier and may not be properly handled by the affine analyses. Reviewed By: wsmoses Differential Revision: https://reviews.llvm.org/D92763 Added: Modified: mlir/lib/Dialect/Affine/Utils/Utils.cpp mlir/test/Dialect/Affine/parallelize.mlir Removed: diff --git a/mlir/lib/Dialect/Affine/Utils/Utils.cpp b/mlir/lib/Dialect/Affine/Utils/Utils.cpp index 7892dfbc7a48..e5f5a6d8998f 100644 --- a/mlir/lib/Dialect/Affine/Utils/Utils.cpp +++ b/mlir/lib/Dialect/Affine/Utils/Utils.cpp @@ -134,11 +134,43 @@ static AffineIfOp hoistAffineIfOp(AffineIfOp ifOp, Operation *hoistOverOp) { void mlir::affineParallelize(AffineForOp forOp) { Location loc = forOp.getLoc(); OpBuilder outsideBuilder(forOp); + + // If a loop has a 'max' in the lower bound, emit it outside the parallel loop + // as it does not have implicit 'max' behavior. + AffineMap lowerBoundMap = forOp.getLowerBoundMap(); + ValueRange lowerBoundOperands = forOp.getLowerBoundOperands(); + AffineMap upperBoundMap = forOp.getUpperBoundMap(); + ValueRange upperBoundOperands = forOp.getUpperBoundOperands(); + + bool needsMax = lowerBoundMap.getNumResults() > 1; + bool needsMin = upperBoundMap.getNumResults() > 1; + AffineMap identityMap; + if (needsMax || needsMin) { +if (forOp->getParentOp() && +!forOp->getParentOp()->hasTrait()) + return; + +identityMap = AffineMap::getMultiDimIdentityMap(1, loc->getContext()); + } + if (needsMax) { +auto maxOp = outsideBuilder.create(loc, lowerBoundMap, +lowerBoundOperands); +lowerBoundMap = identityMap; +lowerBoundOperands = maxOp->getResults(); + } + + // Same for the upper bound. + if (needsMin) { +auto minOp = outsideBuilder.create(loc, upperBoundMap, +upperBoundOperands); +upperBoundMap = identityMap; +upperBoundOperands = minOp->getResults(); + } + // Creating empty 1-D affine.parallel op. AffineParallelOp newPloop = outsideBuilder.create( - loc, llvm::None, llvm::None, forOp.getLowerBoundMap(), - forOp.getLowerBoundOperands(), forOp.getUpperBoundMap(), - forOp.getUpperBoundOperands()); + loc, llvm::None, llvm::None, lowerBoundMap, lowerBoundOperands, + upperBoundMap, upperBoundOperands); // Steal the body of the old affine for op and erase it. newPloop.region().takeBody(forOp.region()); forOp.erase(); diff --git a/mlir/test/Dialect/Affine/parallelize.mlir b/mlir/test/Dialect/Affine/parallelize.mlir index 8e6cb05f46a0..cbc80a092e76 100644 --- a/mlir/test/Dialect/Affine/parallelize.mlir +++ b/mlir/test/Dialect/Affine/parallelize.mlir @@ -114,3 +114,33 @@ func @non_affine_load() { } return } + +// CHECK-LABEL: for_with_minmax +func @for_with_minmax(%m: memref, %lb0: index, %lb1: index, + %ub0: index, %ub1: index) { + // CHECK: %[[lb:.*]] = affine.max + // CHECK: %[[ub:.*]] = affine.min + // CHECK: affine.parallel (%{{.*}}) = (%[[lb]]) to (%[[ub]]) + affine.for %i = max affine_map<(d0, d1) -> (d0, d1)>(%lb0, %lb1) + to min affine_map<(d0, d1) -> (d0, d1)>(%ub0, %ub1) { +affine.load %m[%i] : memref + } + return +} + +// CHECK-LABEL: nested_for_with_minmax +func @nested_for_with_minmax(%m: memref, %lb0: index, + %ub0: index, %ub1: index) { + // CHECK: affine.parallel + affine.for %j = 0 to 10 { +// Cannot parallelize the inner loop because we would need to compute +// affine.max for its lower bound inside the loop, and that is not (yet) +// considered as a valid affine dimension. +// CHECK: affine.for +affine.for %
[llvm-branch-commits] [mlir] 80766ec - [mlir] Add an option to control the number of loops in affine parallelizer
Author: Alex Zinenko Date: 2020-12-08T10:44:37+01:00 New Revision: 80766ecc65096deeb4ff6f03562dcad94c54b862 URL: https://github.com/llvm/llvm-project/commit/80766ecc65096deeb4ff6f03562dcad94c54b862 DIFF: https://github.com/llvm/llvm-project/commit/80766ecc65096deeb4ff6f03562dcad94c54b862.diff LOG: [mlir] Add an option to control the number of loops in affine parallelizer Add a pass option to control the number of nested parallel loops produced by the parallelization passes. This is useful to build end-to-end passes targeting systems that don't need multiple parallel dimensions (e.g., CPUs typically need only one). Reviewed By: wsmoses, chelini Differential Revision: https://reviews.llvm.org/D92765 Added: Modified: mlir/include/mlir/Dialect/Affine/Passes.td mlir/lib/Dialect/Affine/Transforms/AffineParallelize.cpp mlir/test/Dialect/Affine/parallelize.mlir Removed: diff --git a/mlir/include/mlir/Dialect/Affine/Passes.td b/mlir/include/mlir/Dialect/Affine/Passes.td index ace272692d66..9f2aac7b685a 100644 --- a/mlir/include/mlir/Dialect/Affine/Passes.td +++ b/mlir/include/mlir/Dialect/Affine/Passes.td @@ -118,6 +118,11 @@ def AffineVectorize : FunctionPass<"affine-super-vectorize"> { def AffineParallelize : FunctionPass<"affine-parallelize"> { let summary = "Convert affine.for ops into 1-D affine.parallel"; let constructor = "mlir::createAffineParallelizePass()"; + let options = [ +Option<"maxNested", "max-nested", "unsigned", /*default=*/"-1u", + "Maximum number of nested parallel loops to produce. " + "Defaults to unlimited (UINT_MAX).">, + ]; } def AffineLoopNormalize : FunctionPass<"affine-loop-normalize"> { diff --git a/mlir/lib/Dialect/Affine/Transforms/AffineParallelize.cpp b/mlir/lib/Dialect/Affine/Transforms/AffineParallelize.cpp index b3651e202245..d8511be326dd 100644 --- a/mlir/lib/Dialect/Affine/Transforms/AffineParallelize.cpp +++ b/mlir/lib/Dialect/Affine/Transforms/AffineParallelize.cpp @@ -36,13 +36,28 @@ struct AffineParallelize : public AffineParallelizeBase { void AffineParallelize::runOnFunction() { FuncOp f = getFunction(); - SmallVector parallelizableLoops; + + // The walker proceeds in post-order, but we need to process outer loops first + // to control the number of outer parallel loops, so push candidate loops to + // the front of a deque. + std::deque parallelizableLoops; f.walk([&](AffineForOp loop) { if (isLoopParallel(loop)) - parallelizableLoops.push_back(loop); + parallelizableLoops.push_front(loop); }); - for (AffineForOp loop : parallelizableLoops) -affineParallelize(loop); + + for (AffineForOp loop : parallelizableLoops) { +unsigned numParentParallelOps = 0; +for (Operation *op = loop->getParentOp(); + op != nullptr && !op->hasTrait(); + op = op->getParentOp()) { + if (isa(op)) +++numParentParallelOps; +} + +if (numParentParallelOps < maxNested) + affineParallelize(loop); + } } std::unique_ptr> mlir::createAffineParallelizePass() { diff --git a/mlir/test/Dialect/Affine/parallelize.mlir b/mlir/test/Dialect/Affine/parallelize.mlir index cbc80a092e76..08aaa7f32fc8 100644 --- a/mlir/test/Dialect/Affine/parallelize.mlir +++ b/mlir/test/Dialect/Affine/parallelize.mlir @@ -1,4 +1,5 @@ // RUN: mlir-opt %s -allow-unregistered-dialect -affine-parallelize| FileCheck %s +// RUN: mlir-opt %s -allow-unregistered-dialect -affine-parallelize='max-nested=1' | FileCheck --check-prefix=MAX-NESTED %s // CHECK-LABEL:func @reduce_window_max() { func @reduce_window_max() { @@ -144,3 +145,18 @@ func @nested_for_with_minmax(%m: memref, %lb0: index, } return } + +// MAX-NESTED-LABEL: @max_nested +func @max_nested(%m: memref, %lb0: index, %lb1: index, + %ub0: index, %ub1: index) { + // MAX-NESTED: affine.parallel + affine.for %i = affine_map<(d0) -> (d0)>(%lb0) to affine_map<(d0) -> (d0)>(%ub0) { +// MAX-NESTED: affine.for +affine.for %j = affine_map<(d0) -> (d0)>(%lb1) to affine_map<(d0) -> (d0)>(%ub1) { + affine.load %m[%i, %j] : memref +} + } + return +} + + ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] f31704f - [OpenMPIRBuilder] Put the barrier in the exit block in createWorkshapeLoop
Author: Alex Zinenko Date: 2020-12-09T11:33:04+01:00 New Revision: f31704f8ae32a24147fac686f4e922c5c762cfe0 URL: https://github.com/llvm/llvm-project/commit/f31704f8ae32a24147fac686f4e922c5c762cfe0 DIFF: https://github.com/llvm/llvm-project/commit/f31704f8ae32a24147fac686f4e922c5c762cfe0.diff LOG: [OpenMPIRBuilder] Put the barrier in the exit block in createWorkshapeLoop The original code was inserting the barrier at the location given by the caller. Make sure it is always inserted at the end of the loop exit block instead. Reviewed By: Meinersbur Differential Revision: https://reviews.llvm.org/D92849 Added: Modified: llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp Removed: diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 6587a3637c90..609184af6ce8 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -1104,7 +1104,8 @@ CanonicalLoopInfo *OpenMPIRBuilder::createStaticWorkshareLoop( // Add the barrier if requested. if (NeedsBarrier) -createBarrier(Loc, omp::Directive::OMPD_for, /* ForceSimpleCall */ false, +createBarrier(LocationDescription(Builder.saveIP(), Loc.DL), + omp::Directive::OMPD_for, /* ForceSimpleCall */ false, /* CheckCancelFlag */ false); CLI->assertOK(); diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp index 1ad2264d3e39..6e69af725ccb 100644 --- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -1155,6 +1155,13 @@ TEST_F(OpenMPIRBuilderTest, StaticWorkShareLoop) { // increment and in the statement that adds the lower bound to it. Value *IV = CLI->getIndVar(); EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3); + + // The exit block should contain the "fini" call and the barrier call, + // plus the call to obtain the thread ID. + BasicBlock *ExitBlock = CLI->getExit(); + size_t NumCallsInExitBlock = + count_if(*ExitBlock, [](Instruction &I) { return isa(I); }); + EXPECT_EQ(NumCallsInExitBlock, 3u); } TEST_F(OpenMPIRBuilderTest, MasterDirective) { ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] db884da - [mlir] Explicitly track branch instructions in translation to LLVM IR
Author: Alex Zinenko Date: 2020-12-10T11:08:58+01:00 New Revision: db884dafb7b5771e6ae01e8252f1520fac3e1c77 URL: https://github.com/llvm/llvm-project/commit/db884dafb7b5771e6ae01e8252f1520fac3e1c77 DIFF: https://github.com/llvm/llvm-project/commit/db884dafb7b5771e6ae01e8252f1520fac3e1c77.diff LOG: [mlir] Explicitly track branch instructions in translation to LLVM IR The current implementation of the translation to LLVM IR relies on the existence of a one-to-one mapping between MLIR blocks and LLVM IR basic blocks in order to configure PHI nodes with appropriate source blocks. The one-to-one mapping model is broken in presence of OpenMP operations that use LLVM's OpenMPIRBuilder, which produces multiple blocks under the hood. This can lead to invalid LLVM IR being emitted if OpenMPIRBuilder moved the branch operation into a basic block different from the one it was originally created in; specifically, a block that is not a direct predecessor could be used in the PHI node. Instead, keep track of the mapping between MLIR LLVM dialect branch operations and their LLVM IR counterparts and take the parent basic block of the LLVM IR instruction at the moment of connecting the PHI nodes to predecessors. This behavior cannot be triggered as of now, but will be once we introduce the conversion of OpenMP workshare loops. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D92845 Added: Modified: mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h mlir/lib/Target/LLVMIR/ModuleTranslation.cpp Removed: diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 996c8de06e37..d3d289414b38 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -151,6 +151,11 @@ class ModuleTranslation { llvm::StringMap functionMapping; DenseMap valueMapping; DenseMap blockMapping; + + /// A mapping between MLIR LLVM dialect terminators and LLVM IR terminators + /// they are converted to. This allows for conneting PHI nodes to the source + /// values after all operations are converted. + DenseMap branchMapping; }; } // namespace LLVM diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index c20b19f2d5ca..057f57409940 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -340,9 +340,10 @@ static Value getPHISourceValue(Block *current, Block *pred, /// Connect the PHI nodes to the results of preceding blocks. template -static void -connectPHINodes(T &func, const DenseMap &valueMapping, -const DenseMap &blockMapping) { +static void connectPHINodes( +T &func, const DenseMap &valueMapping, +const DenseMap &blockMapping, +const DenseMap &branchMapping) { // Skip the first block, it cannot be branched to and its arguments correspond // to the arguments of the LLVM function. for (auto it = std::next(func.begin()), eit = func.end(); it != eit; ++it) { @@ -355,9 +356,17 @@ connectPHINodes(T &func, const DenseMap &valueMapping, auto &phiNode = numberedPhiNode.value(); unsigned index = numberedPhiNode.index(); for (auto *pred : bb->getPredecessors()) { +// Find the LLVM IR block that contains the converted terminator +// instruction and use it in the PHI node. Note that this block is not +// necessarily the same as blockMapping.lookup(pred), some operations +// (in particular, OpenMP operations using OpenMPIRBuilder) may have +// split the blocks. +llvm::Instruction *terminator = +branchMapping.lookup(pred->getTerminator()); +assert(terminator && "missing the mapping for a terminator"); phiNode.addIncoming(valueMapping.lookup(getPHISourceValue( bb, pred, numArguments, index)), -blockMapping.lookup(pred)); +terminator->getParent()); } } } @@ -476,7 +485,7 @@ void ModuleTranslation::convertOmpOpRegions( } // Finally, after all blocks have been traversed and values mapped, // connect the PHI nodes to the results of preceding blocks. - connectPHINodes(region, valueMapping, blockMapping); + connectPHINodes(region, valueMapping, blockMapping, branchMapping); } LogicalResult ModuleTranslation::convertOmpMaster(Operation &opInst, @@ -682,7 +691,9 @@ LogicalResult ModuleTranslation::convertOperation(Operation &opInst, // Emit branches. We need to look up the remapped blocks and ignore the block // arguments that were transformed into PHI nodes. if (auto brOp = dyn_cast(opInst)) { -builder.CreateBr(blockMapping[brOp.getSuccessor()]); +llvm::BranchInst *branch = +builder.Creat
[llvm-branch-commits] [mlir] dacfb24 - [mlir] Support inlining into affine operations
Author: Alex Zinenko Date: 2020-12-11T16:24:27+01:00 New Revision: dacfb24b301d2f0422f2c7a23e2919e2f35cd932 URL: https://github.com/llvm/llvm-project/commit/dacfb24b301d2f0422f2c7a23e2919e2f35cd932 DIFF: https://github.com/llvm/llvm-project/commit/dacfb24b301d2f0422f2c7a23e2919e2f35cd932.diff LOG: [mlir] Support inlining into affine operations Introduce support for inlining into affine operations. This uses the generic inline infrastructure and boils down to checking that, if applied, the inlining doesn't violate the affine dimension/symbol value categorization. Given valid IR, only the values that are valid dimensions/symbols thanks to being top-level in their affine scope need special handling. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D92770 Added: Modified: mlir/lib/Dialect/Affine/IR/AffineOps.cpp mlir/test/Dialect/Affine/inlining.mlir Removed: diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp index 005db18c54e5..d1d577799b39 100644 --- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp +++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp @@ -9,6 +9,7 @@ #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Affine/IR/AffineValueMap.h" #include "mlir/Dialect/StandardOps/IR/Ops.h" +#include "mlir/IR/BlockAndValueMapping.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/IntegerSet.h" #include "mlir/IR/Matchers.h" @@ -25,6 +26,99 @@ using llvm::dbgs; #define DEBUG_TYPE "affine-analysis" +/// A utility function to check if a value is defined at the top level of +/// `region` or is an argument of `region`. A value of index type defined at the +/// top level of a `AffineScope` region is always a valid symbol for all +/// uses in that region. +static bool isTopLevelValue(Value value, Region *region) { + if (auto arg = value.dyn_cast()) +return arg.getParentRegion() == region; + return value.getDefiningOp()->getParentRegion() == region; +} + +/// Checks if `value` known to be a legal affine dimension or symbol in `src` +/// region remains legal if the operation that uses it is inlined into `dest` +/// with the given value mapping. `legalityCheck` is either `isValidDim` or +/// `isValidSymbol`, depending on the value being required to remain a valid +/// dimension or symbol. +static bool +remainsLegalAfterInline(Value value, Region *src, Region *dest, +const BlockAndValueMapping &mapping, +function_ref legalityCheck) { + // If the value is a valid dimension for any other reason than being + // a top-level value, it will remain valid: constants get inlined + // with the function, transitive affine applies also get inlined and + // will be checked themselves, etc. + if (!isTopLevelValue(value, src)) +return true; + + // If it's a top-level value because it's a block operand, i.e. a + // function argument, check whether the value replacing it after + // inlining is a valid dimension in the new region. + if (value.isa()) +return legalityCheck(mapping.lookup(value), dest); + + // If it's a top-level value beacuse it's defined in the region, + // it can only be inlined if the defining op is a constant or a + // `dim`, which can appear anywhere and be valid, since the defining + // op won't be top-level anymore after inlining. + Attribute operandCst; + return matchPattern(value.getDefiningOp(), m_Constant(&operandCst)) || + value.getDefiningOp(); +} + +/// Checks if all values known to be legal affine dimensions or symbols in `src` +/// remain so if their respective users are inlined into `dest`. +static bool +remainsLegalAfterInline(ValueRange values, Region *src, Region *dest, +const BlockAndValueMapping &mapping, +function_ref legalityCheck) { + return llvm::all_of(values, [&](Value v) { +return remainsLegalAfterInline(v, src, dest, mapping, legalityCheck); + }); +} + +/// Checks if an affine read or write operation remains legal after inlining +/// from `src` to `dest`. +template +static bool remainsLegalAfterInline(OpTy op, Region *src, Region *dest, +const BlockAndValueMapping &mapping) { + static_assert(llvm::is_one_of::value, +"only ops with affine read/write interface are supported"); + + AffineMap map = op.getAffineMap(); + ValueRange dimOperands = op.getMapOperands().take_front(map.getNumDims()); + ValueRange symbolOperands = + op.getMapOperands().take_back(map.getNumSymbols()); + if (!remainsLegalAfterInline( + dimOperands, src, dest, mapping, + static_cast(isValidDim))) +return false; + if (!remainsLegalAfterInline( + symbolOperands, src, dest, mapping, + static_cast(isValidSymbol))) +return false; + return true; +} + +/// Checks if an affine apply operation
[llvm-branch-commits] [mlir] [draft] Dialect Conversion without Rollback (PR #93412)
@@ -1053,3 +1055,241 @@ LogicalResult mlir::applyOpPatternsAndFold( }); return converged; } + +//===--===// +// One-Shot Dialect Conversion Infrastructure +//===--===// + +namespace { +/// A conversion rewriter for the One-Shot Dialect Conversion. This rewriter +/// immediately materializes all IR changes. It derives from +/// `ConversionPatternRewriter` so that the existing conversion patterns can +/// be used with the One-Shot Dialect Conversion. +class OneShotConversionPatternRewriter : public ConversionPatternRewriter { +public: + OneShotConversionPatternRewriter(MLIRContext *ctx) + : ConversionPatternRewriter(ctx) {} + + bool canRecoverFromRewriteFailure() const override { return false; } + + void replaceOp(Operation *op, ValueRange newValues) override; + + void replaceOp(Operation *op, Operation *newOp) override { +replaceOp(op, newOp->getResults()); + } + + void eraseOp(Operation *op) override { PatternRewriter::eraseOp(op); } + + void eraseBlock(Block *block) override { PatternRewriter::eraseBlock(block); } + + void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, + ValueRange argValues = std::nullopt) override { +PatternRewriter::inlineBlockBefore(source, dest, before, argValues); + } + using PatternRewriter::inlineBlockBefore; + + void startOpModification(Operation *op) override { +PatternRewriter::startOpModification(op); + } + + void finalizeOpModification(Operation *op) override { +PatternRewriter::finalizeOpModification(op); + } + + void cancelOpModification(Operation *op) override { +PatternRewriter::cancelOpModification(op); + } + + void setCurrentTypeConverter(const TypeConverter *converter) override { +typeConverter = converter; + } + + const TypeConverter *getCurrentTypeConverter() const override { +return typeConverter; + } + + LogicalResult getAdapterOperands(StringRef valueDiagTag, + std::optional inputLoc, + ValueRange values, + SmallVector &remapped) override; + +private: + /// Build an unrealized_conversion_cast op or look it up in the cache. + Value buildUnrealizedConversionCast(Location loc, Type type, Value value); + + /// The current type converter. + const TypeConverter *typeConverter; + + /// A cache for unrealized_conversion_casts. To ensure that identical casts + /// are not built multiple times. + DenseMap, Value> castCache; ftynse wrote: Hmm, is it possible that the same original value is casted to multiple _different_ types within the same conversion? Type converter is currently unaware of the surrounding context, so it's unclear to me how that could happen. https://github.com/llvm/llvm-project/pull/93412 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [draft] Dialect Conversion without Rollback (PR #93412)
@@ -1819,6 +1822,22 @@ detail::ConversionPatternRewriterImpl &ConversionPatternRewriter::getImpl() { return *impl; } +void ConversionPatternRewriter::setCurrentTypeConverter( +const TypeConverter *converter) { + impl->currentTypeConverter = converter; +} + +const TypeConverter * +ConversionPatternRewriter::getCurrentTypeConverter() const { + return impl->currentTypeConverter; +} + +LogicalResult ConversionPatternRewriter::getAdapterOperands( ftynse wrote: Nit: can we agree on Adapter/Adaptor spelling? E.g., we already have `OpAdaptor`. https://github.com/llvm/llvm-project/pull/93412 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [draft] Dialect Conversion without Rollback (PR #93412)
@@ -321,15 +323,15 @@ class RandomizedWorklist : public Worklist { /// to the worklist in the beginning. class GreedyPatternRewriteDriver : public RewriterBase::Listener { protected: - explicit GreedyPatternRewriteDriver(MLIRContext *ctx, + explicit GreedyPatternRewriteDriver(PatternRewriter &rewriter, const FrozenRewritePatternSet &patterns, const GreedyRewriteConfig &config); /// Add the given operation to the worklist. void addSingleOpToWorklist(Operation *op); /// Add the given operation and its ancestors to the worklist. - void addToWorklist(Operation *op); + virtual void addToWorklist(Operation *op); ftynse wrote: Do we have an estimate of how much overhead adding a vtable to this class introduces? https://github.com/llvm/llvm-project/pull/93412 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [draft] Dialect Conversion without Rollback (PR #93412)
@@ -1053,3 +1055,241 @@ LogicalResult mlir::applyOpPatternsAndFold( }); return converged; } + +//===--===// +// One-Shot Dialect Conversion Infrastructure +//===--===// + +namespace { +/// A conversion rewriter for the One-Shot Dialect Conversion. This rewriter +/// immediately materializes all IR changes. It derives from +/// `ConversionPatternRewriter` so that the existing conversion patterns can +/// be used with the One-Shot Dialect Conversion. +class OneShotConversionPatternRewriter : public ConversionPatternRewriter { +public: + OneShotConversionPatternRewriter(MLIRContext *ctx) + : ConversionPatternRewriter(ctx) {} + + bool canRecoverFromRewriteFailure() const override { return false; } + + void replaceOp(Operation *op, ValueRange newValues) override; + + void replaceOp(Operation *op, Operation *newOp) override { +replaceOp(op, newOp->getResults()); + } + + void eraseOp(Operation *op) override { PatternRewriter::eraseOp(op); } + + void eraseBlock(Block *block) override { PatternRewriter::eraseBlock(block); } + + void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, + ValueRange argValues = std::nullopt) override { +PatternRewriter::inlineBlockBefore(source, dest, before, argValues); + } + using PatternRewriter::inlineBlockBefore; + + void startOpModification(Operation *op) override { +PatternRewriter::startOpModification(op); + } + + void finalizeOpModification(Operation *op) override { +PatternRewriter::finalizeOpModification(op); + } + + void cancelOpModification(Operation *op) override { +PatternRewriter::cancelOpModification(op); + } ftynse wrote: Would these still be necessary after the old driver is removed? https://github.com/llvm/llvm-project/pull/93412 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -3480,6 +3480,31 @@ DiagnosedSilenceableFailure transform::MapCopyToThreadsOp::applyToOne( return DiagnosedSilenceableFailure::success(); } +//===--===// +// WinogradConv2DOp +//===--===// + +DiagnosedSilenceableFailure transform::WinogradConv2DOp::applyToOne( +transform::TransformRewriter &rewriter, linalg::LinalgOp target, +transform::ApplyToEachResultList &results, +transform::TransformState &state) { + rewriter.setInsertionPoint(target); + auto maybeTransformed = + TypeSwitch>(target) + .Case([&](linalg::Conv2DNhwcFhwcOp op) { +return winogradConv2D(rewriter, op, getM(), getR()); + }) + .Default([&](Operation *op) { +return rewriter.notifyMatchFailure(op, "not supported"); ftynse wrote: Let's rather `emitSilenceableFailure()` with this message to the user. The rewriter messages are not printed AFAIK. https://github.com/llvm/llvm-project/pull/96182 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -2587,4 +2587,55 @@ def MapCopyToThreadsOp : }]; } +//===--===// +// Winograd Conv2D +//===--===// + +def WinogradConv2DOp : Op { + let description = [{ +Winograd Conv2D algorithm will convert linalg Conv2D operator into batched ftynse wrote: ```suggestion Winograd Conv2D algorithm will convert linalg Conv2D operation into batched ``` Nit: these are called operations, not operators, in MLIR. https://github.com/llvm/llvm-project/pull/96182 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -0,0 +1,88 @@ +// RUN: mlir-opt %s -transform-interpreter -canonicalize --split-input-file | FileCheck %s + +func.func @conv2d(%arg0: tensor<2x10x10x5xf32>, %arg1: tensor<2x3x3x5xf32>, %arg2: tensor<1xf32>) -> tensor<2x8x8x2xf32> { + %0 = tensor.empty() : tensor<2x8x8x2xf32> + %1 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2, d3) -> (0)>, affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)>], iterator_types = ["parallel", "parallel", "parallel", "parallel"]} ins(%arg2 : tensor<1xf32>) outs(%0 : tensor<2x8x8x2xf32>) { + ^bb0(%in: f32, %out: f32): +linalg.yield %in : f32 + } -> tensor<2x8x8x2xf32> + %2 = linalg.conv_2d_nhwc_fhwc {dilations = dense<1> : tensor<2xi64>, strides = dense<1> : tensor<2xi64>} ins(%arg0, %arg1 : tensor<2x10x10x5xf32>, tensor<2x3x3x5xf32>) outs(%1 : tensor<2x8x8x2xf32>) -> tensor<2x8x8x2xf32> + return %2 : tensor<2x8x8x2xf32> +} + +module attributes {transform.with_named_sequence} { + transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) { +%0 = transform.structured.match ops{["linalg.conv_2d_nhwc_fhwc"]} in %arg1 : (!transform.any_op) -> !transform.any_op +%1 = transform.structured.winograd_conv2d %0 { m = 4, r = 3 } : (!transform.any_op) -> (!transform.any_op) +transform.yield + } +} + +// CHECK: #[[$MAP0:.+]] = affine_map<(d0, d1, d2, d3) -> (0)> +// CHECK: #[[$MAP1:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: func.func @conv2d +// CHECK-SAME: (%[[ARG0:.*]]: tensor<2x10x10x5xf32>, %[[ARG1:.*]]: tensor<2x3x3x5xf32>, %[[ARG2:.*]]: tensor<1xf32>) -> tensor<2x8x8x2xf32> { +// CHECK:%[[S0:.*]] = tensor.empty() : tensor<2x8x8x2xf32> +// CHECK-NEXT: %[[S1:.*]] = linalg.generic {indexing_maps = [#[[$MAP0]], #[[$MAP1]]], iterator_types = ["parallel", "parallel", "parallel", "parallel"]} ins(%[[ARG2]] : tensor<1xf32>) outs(%[[S0]] : tensor<2x8x8x2xf32>) { +// CHECK-NEXT: ^bb0(%[[IN:.*]]: f32, %[[OUT:.*]]: f32): +// CHECK-NEXT: linalg.yield %[[IN]] : f32 +// CHECK-NEXT: } -> tensor<2x8x8x2xf32> +// CHECK-NEXT: %[[S2:.*]] = tensor.empty() : tensor<2x2x6x6x5x2xf32> +// CHECK-NEXT: %[[S3:.*]] = linalg.winograd_filter_transform m(4) r(3) ins(%[[ARG1]] : tensor<2x3x3x5xf32>) outs(%[[S2]] : tensor<2x2x6x6x5x2xf32>) -> tensor<2x2x6x6x5x2xf32> +// CHECK-NEXT: %[[S4:.*]] = tensor.empty() : tensor<2x2x6x6x2x5xf32> +// CHECK-NEXT: %[[S5:.*]] = linalg.winograd_input_transform m(4) r(3) ins(%[[ARG0]] : tensor<2x10x10x5xf32>) outs(%[[S4]] : tensor<2x2x6x6x2x5xf32>) -> tensor<2x2x6x6x2x5xf32> +// CHECK-NEXT: %[[COLLAPSED:.*]] = tensor.collapse_shape %[[S3]] {{\[}}[0, 1, 2, 3], [4], [5]] : tensor<2x2x6x6x5x2xf32> into tensor<144x5x2xf32> +// CHECK-NEXT: %[[COLLAPSED_0:.*]] = tensor.collapse_shape %[[S5]] {{\[}}[0, 1, 2, 3], [4], [5]] : tensor<2x2x6x6x2x5xf32> into tensor<144x2x5xf32> +// CHECK-NEXT: %[[S6:.*]] = tensor.empty() : tensor<144x2x2xf32> +// CHECK-NEXT: %[[S7:.*]] = linalg.batch_matmul ins(%[[COLLAPSED_0]], %[[COLLAPSED]] : tensor<144x2x5xf32>, tensor<144x5x2xf32>) outs(%[[S6]] : tensor<144x2x2xf32>) -> tensor<144x2x2xf32> +// CHECK-NEXT: %[[EXPANDED:.*]] = tensor.expand_shape %[[S7]] {{\[}}[0, 1, 2, 3], [4], [5]] output_shape [2, 2, 6, 6, 2, 2] : tensor<144x2x2xf32> into tensor<2x2x6x6x2x2xf32> +// CHECK-NEXT: %[[S8:.*]] = linalg.winograd_output_transform m(4) r(3) ins(%[[EXPANDED]] : tensor<2x2x6x6x2x2xf32>) outs(%[[S1]] : tensor<2x8x8x2xf32>) -> tensor<2x8x8x2xf32> +// CHECK-NEXT: return %[[S8]] : tensor<2x8x8x2xf32> +// CHECK-NEXT: } ftynse wrote: Since we are already testing the op production logic elsewhere, we don't need to re-test it here. It is sufficient to check that it worked at the high level, e.g.: ``` CHECK: winograd_filter_transform m(4) r(3) CHECK: winograd_input_transform CHECK: match_matmul CHECK: winograd_output_transform ``` https://github.com/llvm/llvm-project/pull/96182 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -2587,4 +2587,55 @@ def MapCopyToThreadsOp : }]; } +//===--===// +// Winograd Conv2D +//===--===// + +def WinogradConv2DOp : Op { + let description = [{ +Winograd Conv2D algorithm will convert linalg Conv2D operator into batched +matrix multiply. Before the matrix multiply, it will convert filter and +input into a format suitable for batched matrix multiply. After the matrix +multiply, it will convert output to the final result tensor. + +The algorithm F(m x m, r x r) is + +Y = A^T x [(G x g x G^T) @ (B^T x d x B)] x A + +The size of output Y is m x m. The size of filter g is r x r. The size of +input d is (m + r - 1) x (m + r - 1). A^T, A, G^T, G, B^T, and B are +transformation matrices. + + Return modes: + +This operation fails if `target` is unsupported. Otherwise, the operation ftynse wrote: ```suggestion This operation produces a silenceable failure if `target` is unsupported. Otherwise, the operation ``` https://github.com/llvm/llvm-project/pull/96182 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -0,0 +1,88 @@ +// RUN: mlir-opt %s -transform-interpreter -canonicalize --split-input-file | FileCheck %s + +func.func @conv2d(%arg0: tensor<2x10x10x5xf32>, %arg1: tensor<2x3x3x5xf32>, %arg2: tensor<1xf32>) -> tensor<2x8x8x2xf32> { + %0 = tensor.empty() : tensor<2x8x8x2xf32> + %1 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2, d3) -> (0)>, affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)>], iterator_types = ["parallel", "parallel", "parallel", "parallel"]} ins(%arg2 : tensor<1xf32>) outs(%0 : tensor<2x8x8x2xf32>) { + ^bb0(%in: f32, %out: f32): +linalg.yield %in : f32 + } -> tensor<2x8x8x2xf32> + %2 = linalg.conv_2d_nhwc_fhwc {dilations = dense<1> : tensor<2xi64>, strides = dense<1> : tensor<2xi64>} ins(%arg0, %arg1 : tensor<2x10x10x5xf32>, tensor<2x3x3x5xf32>) outs(%1 : tensor<2x8x8x2xf32>) -> tensor<2x8x8x2xf32> + return %2 : tensor<2x8x8x2xf32> +} + +module attributes {transform.with_named_sequence} { + transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) { +%0 = transform.structured.match ops{["linalg.conv_2d_nhwc_fhwc"]} in %arg1 : (!transform.any_op) -> !transform.any_op +%1 = transform.structured.winograd_conv2d %0 { m = 4, r = 3 } : (!transform.any_op) -> (!transform.any_op) +transform.yield + } +} + +// CHECK: #[[$MAP0:.+]] = affine_map<(d0, d1, d2, d3) -> (0)> +// CHECK: #[[$MAP1:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: func.func @conv2d +// CHECK-SAME: (%[[ARG0:.*]]: tensor<2x10x10x5xf32>, %[[ARG1:.*]]: tensor<2x3x3x5xf32>, %[[ARG2:.*]]: tensor<1xf32>) -> tensor<2x8x8x2xf32> { +// CHECK:%[[S0:.*]] = tensor.empty() : tensor<2x8x8x2xf32> +// CHECK-NEXT: %[[S1:.*]] = linalg.generic {indexing_maps = [#[[$MAP0]], #[[$MAP1]]], iterator_types = ["parallel", "parallel", "parallel", "parallel"]} ins(%[[ARG2]] : tensor<1xf32>) outs(%[[S0]] : tensor<2x8x8x2xf32>) { +// CHECK-NEXT: ^bb0(%[[IN:.*]]: f32, %[[OUT:.*]]: f32): +// CHECK-NEXT: linalg.yield %[[IN]] : f32 +// CHECK-NEXT: } -> tensor<2x8x8x2xf32> +// CHECK-NEXT: %[[S2:.*]] = tensor.empty() : tensor<2x2x6x6x5x2xf32> +// CHECK-NEXT: %[[S3:.*]] = linalg.winograd_filter_transform m(4) r(3) ins(%[[ARG1]] : tensor<2x3x3x5xf32>) outs(%[[S2]] : tensor<2x2x6x6x5x2xf32>) -> tensor<2x2x6x6x5x2xf32> +// CHECK-NEXT: %[[S4:.*]] = tensor.empty() : tensor<2x2x6x6x2x5xf32> +// CHECK-NEXT: %[[S5:.*]] = linalg.winograd_input_transform m(4) r(3) ins(%[[ARG0]] : tensor<2x10x10x5xf32>) outs(%[[S4]] : tensor<2x2x6x6x2x5xf32>) -> tensor<2x2x6x6x2x5xf32> +// CHECK-NEXT: %[[COLLAPSED:.*]] = tensor.collapse_shape %[[S3]] {{\[}}[0, 1, 2, 3], [4], [5]] : tensor<2x2x6x6x5x2xf32> into tensor<144x5x2xf32> +// CHECK-NEXT: %[[COLLAPSED_0:.*]] = tensor.collapse_shape %[[S5]] {{\[}}[0, 1, 2, 3], [4], [5]] : tensor<2x2x6x6x2x5xf32> into tensor<144x2x5xf32> +// CHECK-NEXT: %[[S6:.*]] = tensor.empty() : tensor<144x2x2xf32> +// CHECK-NEXT: %[[S7:.*]] = linalg.batch_matmul ins(%[[COLLAPSED_0]], %[[COLLAPSED]] : tensor<144x2x5xf32>, tensor<144x5x2xf32>) outs(%[[S6]] : tensor<144x2x2xf32>) -> tensor<144x2x2xf32> +// CHECK-NEXT: %[[EXPANDED:.*]] = tensor.expand_shape %[[S7]] {{\[}}[0, 1, 2, 3], [4], [5]] output_shape [2, 2, 6, 6, 2, 2] : tensor<144x2x2xf32> into tensor<2x2x6x6x2x2xf32> +// CHECK-NEXT: %[[S8:.*]] = linalg.winograd_output_transform m(4) r(3) ins(%[[EXPANDED]] : tensor<2x2x6x6x2x2xf32>) outs(%[[S1]] : tensor<2x8x8x2xf32>) -> tensor<2x8x8x2xf32> +// CHECK-NEXT: return %[[S8]] : tensor<2x8x8x2xf32> +// CHECK-NEXT: } + +// - + +func.func @conv2d_unaligned(%arg0: tensor<2x11x11x5xf32>, %arg1: tensor<2x3x3x5xf32>, %arg2: tensor<1xf32>) -> tensor<2x9x9x2xf32> { + %0 = tensor.empty() : tensor<2x9x9x2xf32> + %1 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2, d3) -> (0)>, affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)>], iterator_types = ["parallel", "parallel", "parallel", "parallel"]} ins(%arg2 : tensor<1xf32>) outs(%0 : tensor<2x9x9x2xf32>) { + ^bb0(%in: f32, %out: f32): +linalg.yield %in : f32 + } -> tensor<2x9x9x2xf32> + %2 = linalg.conv_2d_nhwc_fhwc {dilations = dense<1> : tensor<2xi64>, strides = dense<1> : tensor<2xi64>} ins(%arg0, %arg1 : tensor<2x11x11x5xf32>, tensor<2x3x3x5xf32>) outs(%1 : tensor<2x9x9x2xf32>) -> tensor<2x9x9x2xf32> + return %2 : tensor<2x9x9x2xf32> +} + +module attributes {transform.with_named_sequence} { + transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) { +%0 = transform.structured.match ops{["linalg.conv_2d_nhwc_fhwc"]} in %arg1 : (!transform.any_op) -> !transform.any_op +%1 = transform.structured.winograd_conv2d %0 { m = 4, r = 3 } : (!transform.any_op) -> (!transform.any_op) +transform.yield + } +} + +// CHECK: #[[$MAP0:.+]] = affine_map<(d0, d1, d2, d3) -> (0)> +// CHECK: #[[$MAP1:.+]] = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: func.func @conv2d_unaligned
[llvm-branch-commits] [mlir] [mlir][linalg] Add transform operator for Winograd Conv2D algorithm (PR #96182)
@@ -3480,6 +3480,31 @@ DiagnosedSilenceableFailure transform::MapCopyToThreadsOp::applyToOne( return DiagnosedSilenceableFailure::success(); } +//===--===// +// WinogradConv2DOp +//===--===// + +DiagnosedSilenceableFailure transform::WinogradConv2DOp::applyToOne( +transform::TransformRewriter &rewriter, linalg::LinalgOp target, +transform::ApplyToEachResultList &results, +transform::TransformState &state) { + rewriter.setInsertionPoint(target); + auto maybeTransformed = + TypeSwitch>(target) + .Case([&](linalg::Conv2DNhwcFhwcOp op) { +return winogradConv2D(rewriter, op, getM(), getR()); + }) + .Default([&](Operation *op) { +return rewriter.notifyMatchFailure(op, "not supported"); + }); + + if (failed(maybeTransformed)) +return emitDefaultSilenceableFailure(target); ftynse wrote: It would be nice if `windogradConv2D` was returning some error code or was taking a callback to print error messages to instead of giving a default message here. Non-blocking. https://github.com/llvm/llvm-project/pull/96182 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -36,6 +189,92 @@ constexpr TransformMapKeyTy F_2_3{2, 3}; constexpr TransformMapKeyTy F_4_3{4, 3}; constexpr TransformMapKeyTy F_2_5{2, 5}; +struct TransformMatrix { ftynse wrote: Please document top-level entities. https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -23,6 +26,156 @@ namespace linalg { namespace { +// clang-format off +// Winograd Conv2D uses a minimal 2D filtering algorithm to calculate its +// result. The formula of minimal 2D filtering algorithm F(m x m, r x r), +// m is the output dimension and r is the filter dimension, is +// +// Y = A^T x [ (G x g x G^T) x (B^T x d x B) ] x A +// +// g is filter and d is input data. We need to prepare 6 constant +// transformation matrices, G, G^T, B^T, B, A^T, and A for this formula. +// +// The following tables define these constant transformation matrices for +// F(2 x 2, 3 x 3), F(4 x 4, 3 x 3), and F(2 x 2, 5 x 5) +constexpr float G_2x2_3x3[] = { + -1, 0, 0, + 1./2, -1./2, 1./2, + 1./2, 1./2, 1./2, +0, 0,1 +}; + +constexpr float GT_2x2_3x3[] = { + -1, 1./2, 1./2, 0, +0, -1./2, 1./2, 0, +0, 1./2, 1./2, 1 +}; ftynse wrote: Have you considered introducing a (potentially `constexpr`) transpose function or some sort of transposed access iterator instead of hardcoding transposed matrices? https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -48,6 +287,261 @@ Value collapse2DData(RewriterBase &rewriter, Location loc, Value data) { reassociation); } +// This function transforms the filter. The data layout of the filter is FHWC. +// The transformation matrix is 2-dimension. We need to extract H x W from +// FHWC first. We need to generate 2 levels of loops to iterate on F and C. +// After the transformation, we get +// +// scf.for %f = lo_f to hi_f step 1 +// scf.for %c = lo_c to hi_c step 1 +// %extracted = extract filter from filter +// %ret = linalg.matmul G, %extracted +// %ret = linalg.matmul %ret, GT +// %inserted = insert %ret into filter +// +Value filterTransform(RewriterBase &rewriter, Location loc, Value filter, + Value retValue, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to G transform matrix. + static const llvm::SmallDenseMap + GMatrices = { + {F_2_3, TransformMatrix(G_2x2_3x3, 4, 3)}, + {F_4_3, TransformMatrix(G_4x4_3x3, 6, 3)}, + {F_2_5, TransformMatrix(G_2x2_5x5, 6, 5)}, + }; + + // Map from (m, r) to GT transform matrix. + static const llvm::SmallDenseMap + GTMatrices = { + {F_2_3, TransformMatrix(GT_2x2_3x3, 3, 4)}, + {F_4_3, TransformMatrix(GT_4x4_3x3, 3, 6)}, + {F_2_5, TransformMatrix(GT_2x2_5x5, 5, 6)}, + }; + + auto filterType = cast(filter.getType()); + Type elementType = filterType.getElementType(); + auto filterShape = filterType.getShape(); // F, H, W, C + int64_t filterF = filterShape[0]; + int64_t filterH = filterShape[1]; + int64_t filterW = filterShape[2]; + int64_t filterC = filterShape[3]; + + if (filterH != r && filterH != 1) +return Value(); + if (filterW != r && filterW != 1) +return Value(); + + // Return shape is + auto zeroIdx = rewriter.create(loc, 0); + auto fUpperBound = rewriter.create(loc, filterF); + auto cUpperBound = rewriter.create(loc, filterC); + auto oneStep = rewriter.create(loc, 1); + auto outerForOp = + rewriter.create(loc, zeroIdx, fUpperBound, oneStep, retValue); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value FIter = outerForBody->getArgument(0); + + auto innerForOp = rewriter.create( + loc, zeroIdx, cUpperBound, oneStep, outerForOp.getRegionIterArgs()[0]); ftynse wrote: Ditto. there must be a better-named function for this. https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -48,6 +287,261 @@ Value collapse2DData(RewriterBase &rewriter, Location loc, Value data) { reassociation); } +// This function transforms the filter. The data layout of the filter is FHWC. +// The transformation matrix is 2-dimension. We need to extract H x W from +// FHWC first. We need to generate 2 levels of loops to iterate on F and C. +// After the transformation, we get +// +// scf.for %f = lo_f to hi_f step 1 +// scf.for %c = lo_c to hi_c step 1 +// %extracted = extract filter from filter +// %ret = linalg.matmul G, %extracted +// %ret = linalg.matmul %ret, GT +// %inserted = insert %ret into filter +// +Value filterTransform(RewriterBase &rewriter, Location loc, Value filter, + Value retValue, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to G transform matrix. + static const llvm::SmallDenseMap + GMatrices = { + {F_2_3, TransformMatrix(G_2x2_3x3, 4, 3)}, + {F_4_3, TransformMatrix(G_4x4_3x3, 6, 3)}, + {F_2_5, TransformMatrix(G_2x2_5x5, 6, 5)}, + }; + + // Map from (m, r) to GT transform matrix. + static const llvm::SmallDenseMap + GTMatrices = { + {F_2_3, TransformMatrix(GT_2x2_3x3, 3, 4)}, + {F_4_3, TransformMatrix(GT_4x4_3x3, 3, 6)}, + {F_2_5, TransformMatrix(GT_2x2_5x5, 5, 6)}, + }; + + auto filterType = cast(filter.getType()); + Type elementType = filterType.getElementType(); + auto filterShape = filterType.getShape(); // F, H, W, C + int64_t filterF = filterShape[0]; + int64_t filterH = filterShape[1]; + int64_t filterW = filterShape[2]; + int64_t filterC = filterShape[3]; + + if (filterH != r && filterH != 1) +return Value(); + if (filterW != r && filterW != 1) +return Value(); + + // Return shape is + auto zeroIdx = rewriter.create(loc, 0); + auto fUpperBound = rewriter.create(loc, filterF); + auto cUpperBound = rewriter.create(loc, filterC); + auto oneStep = rewriter.create(loc, 1); + auto outerForOp = + rewriter.create(loc, zeroIdx, fUpperBound, oneStep, retValue); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value FIter = outerForBody->getArgument(0); + + auto innerForOp = rewriter.create( + loc, zeroIdx, cUpperBound, oneStep, outerForOp.getRegionIterArgs()[0]); + Block *innerForBody = innerForOp.getBody(); + rewriter.setInsertionPointToStart(innerForBody); + Value CIter = innerForBody->getArgument(0); + + // Extract (H, W) from (F, H, W, C) + auto extractFilter = extract2DData( + rewriter, loc, filter, FIter, CIter, /*outLoopIdx=*/0, + /*inLoopIdx=*/3, /*heightIdx=*/1, /*widthIdx=*/2, /*srcSize=*/4); + + TransformMapKeyTy key = {m, r}; + int64_t retRows = 1; + Value matmulRetValue = extractFilter; + if (leftTransform) { +// Get constant transform matrix G +auto it = GMatrices.find(key); +if (it == GMatrices.end()) + return Value(); +const TransformMatrix &GMatrix = it->second; + +retRows = GMatrix.rows; +auto matmulType = RankedTensorType::get({retRows, filterW}, elementType); +auto init = rewriter.create(loc, matmulType.getShape(), + elementType); + +Value G = create2DTransformMatrix(rewriter, loc, GMatrix, elementType); ftynse wrote: I wonder if we rather want to provide these matrices as global memrefs instead of creating locally every time. Have you considered that? https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -323,5 +1089,12 @@ void populateWinogradConv2DPatterns(RewritePatternSet &patterns, int64_t m, patterns.insert(context, m, r); } +void populateDecomposeWinogradOpsPatterns(RewritePatternSet &patterns) { + MLIRContext *context = patterns.getContext(); + patterns.insert(context); + patterns.insert(context); + patterns.insert(context); ftynse wrote: ```suggestion patterns.insert(context); ``` https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -100,6 +594,161 @@ Value matrixMultiply(RewriterBase &rewriter, Location loc, return expandOutput; } +// This function transforms the output. The data layout of the output is HWNF. +// The transformation matrix is 2-dimension. We need to extract H x W from +// HWNF first. We need to generate 2 levels of loops to iterate on N and F. +// After the transformation, we get +// +// scf.for %n = lo_n to hi_n step 1 +// scf.for %f = lo_f to hi_f step 1 +// %extracted = extract input from result +// %ret = linalg.matmul AT, %extracted +// %ret = linalg.matmul %ret, A +// %inserted = insert %ret into ret +// +Value outputTransform(RewriterBase &rewriter, Location loc, Value value, + Value output, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to AT transform matrix. + static const llvm::SmallDenseMap + ATMatrices = { + {F_2_3, TransformMatrix(AT_2x2_3x3, 2, 4)}, + {F_4_3, TransformMatrix(AT_4x4_3x3, 4, 6, 32)}, + {F_2_5, TransformMatrix(AT_2x2_5x5, 2, 6, 16)}, + }; + + // Map from (m, r) to A transform matrix. + static const llvm::SmallDenseMap + AMatrices = { + {F_2_3, TransformMatrix(A_2x2_3x3, 4, 2)}, + {F_4_3, TransformMatrix(A_4x4_3x3, 6, 4, 32)}, + {F_2_5, TransformMatrix(A_2x2_5x5, 6, 2, 16)}, + }; + + auto valueType = cast(value.getType()); + Type elementType = valueType.getElementType(); + auto valueShape = valueType.getShape(); // TileH, TileW, H, W, N, F + int64_t valueH = valueShape[2]; + int64_t valueW = valueShape[3]; + int64_t valueN = valueShape[4]; + int64_t valueF = valueShape[5]; + int64_t alphaH = leftTransform ? m + r - 1 : 1; + int64_t alphaW = rightTransform ? m + r - 1 : 1; + + if (valueH != alphaH && valueH != 1) +return Value(); + if (valueW != alphaW && valueW != 1) +return Value(); + + auto zeroIdx = rewriter.create(loc, 0); + auto nUpperBound = rewriter.create(loc, valueN); + auto fUpperBound = rewriter.create(loc, valueF); + auto oneStep = rewriter.create(loc, 1); + + auto outerForOp = + rewriter.create(loc, zeroIdx, nUpperBound, oneStep, output); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value NIter = outerForBody->getArgument(0); + + auto innerForOp = rewriter.create( + loc, zeroIdx, fUpperBound, oneStep, outerForOp.getRegionIterArgs()[0]); + Block *innerForBody = innerForOp.getBody(); + rewriter.setInsertionPointToStart(innerForBody); + Value FIter = innerForBody->getArgument(0); + + // Extract (H, W) from (1, 1, H, W, N, F) + auto extractValue = extract2DData( + rewriter, loc, value, NIter, FIter, /*outLoopIdx=*/4, + /*inLoopIdx=*/5, /*heightIdx=*/2, /*widthIdx=*/3, /*srcSize=*/6); + + TransformMapKeyTy key = {m, r}; + int64_t retRows = 1; + int64_t retCols = 1; + int64_t leftScalarFactor = 1; + int64_t rightScalarFactor = 1; + Value matmulRetValue = extractValue; + if (leftTransform) { +// Get constant transform matrix AT +auto it = ATMatrices.find(key); +if (it == ATMatrices.end()) + return Value(); +const TransformMatrix &ATMatrix = it->second; + +leftScalarFactor = ATMatrix.scalarFactor; +retRows = ATMatrix.rows; +auto matmulType = RankedTensorType::get({retRows, valueW}, elementType); +auto init = rewriter.create(loc, matmulType.getShape(), + elementType); + +Value AT = create2DTransformMatrix(rewriter, loc, ATMatrix, elementType); +// Multiply AT x m +auto matmulOp = rewriter.create( +loc, matmulType, ValueRange{AT, matmulRetValue}, ValueRange{init}); +matmulRetValue = matmulOp.getResult(0); + } + + if (rightTransform) { +// Get constant transform matrix T +auto it = AMatrices.find(key); +if (it == AMatrices.end()) + return Value(); +const TransformMatrix &AMatrix = it->second; + +rightScalarFactor = AMatrix.scalarFactor; +auto matmulType = +RankedTensorType::get({retRows, AMatrix.cols}, elementType); +retCols = AMatrix.cols; +auto init = rewriter.create(loc, matmulType.getShape(), + elementType); + +Value A = create2DTransformMatrix(rewriter, loc, AMatrix, elementType); +// Multiply y = (AT x m) x A +auto matmulOp = rewriter.create( +loc, matmulType, ValueRange{matmulRetValue, A}, ValueRange{init}); +matmulRetValue = matmulOp.getResult(0); + } + + // Multiply scalar factor. + Value scalarFactor = rewriter.create( + loc, FloatAttr::get(elementType, leftScalarFactor * rightScalarFactor)); + auto matmulType = RankedTensorType::get({retRows, retCols}, elementType); + auto init = + rewriter.create(loc, matmulType.getShape(), elementType); + + auto identityAffineMap = rewriter.getMultiDimIdentityMap(2); + Smal
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -100,6 +594,161 @@ Value matrixMultiply(RewriterBase &rewriter, Location loc, return expandOutput; } +// This function transforms the output. The data layout of the output is HWNF. +// The transformation matrix is 2-dimension. We need to extract H x W from +// HWNF first. We need to generate 2 levels of loops to iterate on N and F. +// After the transformation, we get +// +// scf.for %n = lo_n to hi_n step 1 +// scf.for %f = lo_f to hi_f step 1 +// %extracted = extract input from result +// %ret = linalg.matmul AT, %extracted +// %ret = linalg.matmul %ret, A +// %inserted = insert %ret into ret +// +Value outputTransform(RewriterBase &rewriter, Location loc, Value value, + Value output, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to AT transform matrix. + static const llvm::SmallDenseMap + ATMatrices = { + {F_2_3, TransformMatrix(AT_2x2_3x3, 2, 4)}, + {F_4_3, TransformMatrix(AT_4x4_3x3, 4, 6, 32)}, + {F_2_5, TransformMatrix(AT_2x2_5x5, 2, 6, 16)}, + }; + + // Map from (m, r) to A transform matrix. + static const llvm::SmallDenseMap + AMatrices = { + {F_2_3, TransformMatrix(A_2x2_3x3, 4, 2)}, + {F_4_3, TransformMatrix(A_4x4_3x3, 6, 4, 32)}, + {F_2_5, TransformMatrix(A_2x2_5x5, 6, 2, 16)}, + }; + + auto valueType = cast(value.getType()); + Type elementType = valueType.getElementType(); + auto valueShape = valueType.getShape(); // TileH, TileW, H, W, N, F + int64_t valueH = valueShape[2]; + int64_t valueW = valueShape[3]; + int64_t valueN = valueShape[4]; + int64_t valueF = valueShape[5]; + int64_t alphaH = leftTransform ? m + r - 1 : 1; + int64_t alphaW = rightTransform ? m + r - 1 : 1; + + if (valueH != alphaH && valueH != 1) +return Value(); + if (valueW != alphaW && valueW != 1) +return Value(); + + auto zeroIdx = rewriter.create(loc, 0); + auto nUpperBound = rewriter.create(loc, valueN); + auto fUpperBound = rewriter.create(loc, valueF); + auto oneStep = rewriter.create(loc, 1); + + auto outerForOp = + rewriter.create(loc, zeroIdx, nUpperBound, oneStep, output); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value NIter = outerForBody->getArgument(0); + + auto innerForOp = rewriter.create( + loc, zeroIdx, fUpperBound, oneStep, outerForOp.getRegionIterArgs()[0]); + Block *innerForBody = innerForOp.getBody(); + rewriter.setInsertionPointToStart(innerForBody); + Value FIter = innerForBody->getArgument(0); + + // Extract (H, W) from (1, 1, H, W, N, F) + auto extractValue = extract2DData( + rewriter, loc, value, NIter, FIter, /*outLoopIdx=*/4, + /*inLoopIdx=*/5, /*heightIdx=*/2, /*widthIdx=*/3, /*srcSize=*/6); + + TransformMapKeyTy key = {m, r}; + int64_t retRows = 1; + int64_t retCols = 1; + int64_t leftScalarFactor = 1; + int64_t rightScalarFactor = 1; + Value matmulRetValue = extractValue; + if (leftTransform) { +// Get constant transform matrix AT +auto it = ATMatrices.find(key); +if (it == ATMatrices.end()) + return Value(); +const TransformMatrix &ATMatrix = it->second; + +leftScalarFactor = ATMatrix.scalarFactor; +retRows = ATMatrix.rows; +auto matmulType = RankedTensorType::get({retRows, valueW}, elementType); +auto init = rewriter.create(loc, matmulType.getShape(), + elementType); + +Value AT = create2DTransformMatrix(rewriter, loc, ATMatrix, elementType); +// Multiply AT x m +auto matmulOp = rewriter.create( +loc, matmulType, ValueRange{AT, matmulRetValue}, ValueRange{init}); +matmulRetValue = matmulOp.getResult(0); + } + + if (rightTransform) { +// Get constant transform matrix T +auto it = AMatrices.find(key); +if (it == AMatrices.end()) + return Value(); +const TransformMatrix &AMatrix = it->second; + +rightScalarFactor = AMatrix.scalarFactor; +auto matmulType = +RankedTensorType::get({retRows, AMatrix.cols}, elementType); +retCols = AMatrix.cols; +auto init = rewriter.create(loc, matmulType.getShape(), + elementType); + +Value A = create2DTransformMatrix(rewriter, loc, AMatrix, elementType); +// Multiply y = (AT x m) x A +auto matmulOp = rewriter.create( +loc, matmulType, ValueRange{matmulRetValue, A}, ValueRange{init}); +matmulRetValue = matmulOp.getResult(0); + } + + // Multiply scalar factor. + Value scalarFactor = rewriter.create( + loc, FloatAttr::get(elementType, leftScalarFactor * rightScalarFactor)); + auto matmulType = RankedTensorType::get({retRows, retCols}, elementType); + auto init = + rewriter.create(loc, matmulType.getShape(), elementType); + + auto identityAffineMap = rewriter.getMultiDimIdentityMap(2); + Smal
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -100,6 +594,161 @@ Value matrixMultiply(RewriterBase &rewriter, Location loc, return expandOutput; } +// This function transforms the output. The data layout of the output is HWNF. +// The transformation matrix is 2-dimension. We need to extract H x W from +// HWNF first. We need to generate 2 levels of loops to iterate on N and F. +// After the transformation, we get +// +// scf.for %n = lo_n to hi_n step 1 +// scf.for %f = lo_f to hi_f step 1 +// %extracted = extract input from result +// %ret = linalg.matmul AT, %extracted +// %ret = linalg.matmul %ret, A +// %inserted = insert %ret into ret +// +Value outputTransform(RewriterBase &rewriter, Location loc, Value value, + Value output, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to AT transform matrix. + static const llvm::SmallDenseMap + ATMatrices = { + {F_2_3, TransformMatrix(AT_2x2_3x3, 2, 4)}, + {F_4_3, TransformMatrix(AT_4x4_3x3, 4, 6, 32)}, + {F_2_5, TransformMatrix(AT_2x2_5x5, 2, 6, 16)}, + }; + + // Map from (m, r) to A transform matrix. + static const llvm::SmallDenseMap + AMatrices = { + {F_2_3, TransformMatrix(A_2x2_3x3, 4, 2)}, + {F_4_3, TransformMatrix(A_4x4_3x3, 6, 4, 32)}, + {F_2_5, TransformMatrix(A_2x2_5x5, 6, 2, 16)}, + }; + + auto valueType = cast(value.getType()); + Type elementType = valueType.getElementType(); + auto valueShape = valueType.getShape(); // TileH, TileW, H, W, N, F + int64_t valueH = valueShape[2]; + int64_t valueW = valueShape[3]; + int64_t valueN = valueShape[4]; + int64_t valueF = valueShape[5]; + int64_t alphaH = leftTransform ? m + r - 1 : 1; + int64_t alphaW = rightTransform ? m + r - 1 : 1; + + if (valueH != alphaH && valueH != 1) +return Value(); + if (valueW != alphaW && valueW != 1) +return Value(); + + auto zeroIdx = rewriter.create(loc, 0); + auto nUpperBound = rewriter.create(loc, valueN); + auto fUpperBound = rewriter.create(loc, valueF); + auto oneStep = rewriter.create(loc, 1); + + auto outerForOp = + rewriter.create(loc, zeroIdx, nUpperBound, oneStep, output); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value NIter = outerForBody->getArgument(0); + + auto innerForOp = rewriter.create( + loc, zeroIdx, fUpperBound, oneStep, outerForOp.getRegionIterArgs()[0]); + Block *innerForBody = innerForOp.getBody(); + rewriter.setInsertionPointToStart(innerForBody); + Value FIter = innerForBody->getArgument(0); ftynse wrote: FYI, there's a `mlir::scf::buildLoopNest` somewhere that may space you the boilerplate. https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -48,6 +287,261 @@ Value collapse2DData(RewriterBase &rewriter, Location loc, Value data) { reassociation); } +// This function transforms the filter. The data layout of the filter is FHWC. +// The transformation matrix is 2-dimension. We need to extract H x W from +// FHWC first. We need to generate 2 levels of loops to iterate on F and C. +// After the transformation, we get +// +// scf.for %f = lo_f to hi_f step 1 +// scf.for %c = lo_c to hi_c step 1 +// %extracted = extract filter from filter +// %ret = linalg.matmul G, %extracted +// %ret = linalg.matmul %ret, GT +// %inserted = insert %ret into filter +// ftynse wrote: ```suggestion /// This function transforms the filter. The data layout of the filter is FHWC. /// The transformation matrix is 2-dimension. We need to extract H x W from /// FHWC first. We need to generate 2 levels of loops to iterate on F and C. /// After the transformation, we get /// /// scf.for %f = lo_f to hi_f step 1 /// scf.for %c = lo_c to hi_c step 1 /// %extracted = extract filter from filter /// %ret = linalg.matmul G, %extracted /// %ret = linalg.matmul %ret, GT /// %inserted = insert %ret into filter /// ``` https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -289,6 +938,123 @@ FailureOr winogradConv2DHelper(RewriterBase &rewriter, return transformedOutput.getDefiningOp(); } +FailureOr +decomposeWinogradFilterTransformHelper(RewriterBase &rewriter, + linalg::WinogradFilterTransformOp op) { + Location loc = op.getLoc(); + Value filter = op.getFilter(); + auto filterType = cast(filter.getType()); + auto filterShape = filterType.getShape(); + int64_t filterH = filterShape[1]; + int64_t filterW = filterShape[2]; + + // For F(m x 1, r x 1), we only need to do left side transform. + bool leftTransform = filterH != 1; + // For F(1 x m, 1 x r), we only need to do right side transform. + bool rightTransform = filterW != 1; + Value transformedFilter = + filterTransform(rewriter, loc, filter, op.getOutput(), op.getM(), + op.getR(), leftTransform, rightTransform); + if (!transformedFilter) +return failure(); + + rewriter.replaceOp(op, transformedFilter); + + return transformedFilter.getDefiningOp(); +} + +FailureOr +decomposeWinogradInputTransformHelper(RewriterBase &rewriter, + linalg::WinogradInputTransformOp op) { + Location loc = op.getLoc(); + Value input = op.getInput(); + auto inputType = cast(input.getType()); + auto inputShape = inputType.getShape(); + int64_t inputH = inputShape[1]; + int64_t inputW = inputShape[2]; + + // For F(m x 1, r x 1), we only need to do left side transform. + bool leftTransform = inputH != 1; + // For F(1 x m, 1 x r), we only need to do right side transform. + bool rightTransform = inputW != 1; + Value transformedInput = + inputTransform(rewriter, loc, op.getInput(), op.getOutput(), op.getM(), + op.getR(), leftTransform, rightTransform); + if (!transformedInput) +return failure(); + + rewriter.replaceOp(op, transformedInput); + + return transformedInput.getDefiningOp(); +} + +FailureOr +decomposeWinogradOutputTransformHelper(RewriterBase &rewriter, + linalg::WinogradOutputTransformOp op) { + Location loc = op.getLoc(); + Value value = op.getValue(); + auto valueType = cast(value.getType()); + auto valueShape = valueType.getShape(); + int64_t valueH = valueShape[2]; + int64_t valueW = valueShape[3]; + + // For F(m x 1, r x 1), we only need to do left side transform. + bool leftTransform = valueH != 1; + // For F(1 x m, 1 x r), we only need to do right side transform. + bool rightTransform = valueW != 1; + Value transformedOutput = + outputTransform(rewriter, loc, value, op.getOutput(), op.getM(), + op.getR(), leftTransform, rightTransform); + if (!transformedOutput) +return failure(); + + rewriter.replaceOp(op, transformedOutput); + + return transformedOutput.getDefiningOp(); +} + +class DecomposeWinogradFilterTransform final +: public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(linalg::WinogradFilterTransformOp op, +PatternRewriter &rewriter) const override { +if (failed(decomposeWinogradFilterTransformHelper(rewriter, op))) + return failure(); + +return success(); + } +}; + +class DecomposeWinogradInputTransform final +: public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(linalg::WinogradInputTransformOp op, +PatternRewriter &rewriter) const override { +if (failed(decomposeWinogradInputTransformHelper(rewriter, op))) + return failure(); + +return success(); ftynse wrote: ```suggestion return decomposeWinogradInputTransformHelper(rewriter, op); ``` https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -36,6 +189,92 @@ constexpr TransformMapKeyTy F_2_3{2, 3}; constexpr TransformMapKeyTy F_4_3{4, 3}; constexpr TransformMapKeyTy F_2_5{2, 5}; +struct TransformMatrix { + TransformMatrix(const float *table, int64_t rows, int64_t cols, + int64_t scalarFactor = 1) + : table(table), rows(rows), cols(cols), scalarFactor(scalarFactor) {} + + const float *table; + int64_t rows; + int64_t cols; + int64_t scalarFactor; +}; + +Value create2DTransformMatrix(RewriterBase &rewriter, Location loc, + TransformMatrix transform, Type type) { + ArrayRef const_vec(transform.table, transform.rows * transform.cols); ftynse wrote: Nit: camelBack ```suggestion ArrayRef constVec(transform.table, transform.rows * transform.cols); ``` https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Decompose winograd operators (PR #96183)
@@ -48,6 +287,261 @@ Value collapse2DData(RewriterBase &rewriter, Location loc, Value data) { reassociation); } +// This function transforms the filter. The data layout of the filter is FHWC. +// The transformation matrix is 2-dimension. We need to extract H x W from +// FHWC first. We need to generate 2 levels of loops to iterate on F and C. +// After the transformation, we get +// +// scf.for %f = lo_f to hi_f step 1 +// scf.for %c = lo_c to hi_c step 1 +// %extracted = extract filter from filter +// %ret = linalg.matmul G, %extracted +// %ret = linalg.matmul %ret, GT +// %inserted = insert %ret into filter +// +Value filterTransform(RewriterBase &rewriter, Location loc, Value filter, + Value retValue, int64_t m, int64_t r, + bool leftTransform = true, bool rightTransform = true) { + // Map from (m, r) to G transform matrix. + static const llvm::SmallDenseMap + GMatrices = { + {F_2_3, TransformMatrix(G_2x2_3x3, 4, 3)}, + {F_4_3, TransformMatrix(G_4x4_3x3, 6, 3)}, + {F_2_5, TransformMatrix(G_2x2_5x5, 6, 5)}, + }; + + // Map from (m, r) to GT transform matrix. + static const llvm::SmallDenseMap + GTMatrices = { + {F_2_3, TransformMatrix(GT_2x2_3x3, 3, 4)}, + {F_4_3, TransformMatrix(GT_4x4_3x3, 3, 6)}, + {F_2_5, TransformMatrix(GT_2x2_5x5, 5, 6)}, + }; + + auto filterType = cast(filter.getType()); + Type elementType = filterType.getElementType(); + auto filterShape = filterType.getShape(); // F, H, W, C + int64_t filterF = filterShape[0]; + int64_t filterH = filterShape[1]; + int64_t filterW = filterShape[2]; + int64_t filterC = filterShape[3]; + + if (filterH != r && filterH != 1) +return Value(); + if (filterW != r && filterW != 1) +return Value(); + + // Return shape is + auto zeroIdx = rewriter.create(loc, 0); + auto fUpperBound = rewriter.create(loc, filterF); + auto cUpperBound = rewriter.create(loc, filterC); + auto oneStep = rewriter.create(loc, 1); + auto outerForOp = + rewriter.create(loc, zeroIdx, fUpperBound, oneStep, retValue); + Block *outerForBody = outerForOp.getBody(); + rewriter.setInsertionPointToStart(outerForBody); + Value FIter = outerForBody->getArgument(0); ftynse wrote: There must be a function on `scf::ForOp` that returns the induction variable and avoids magic constant zero here. https://github.com/llvm/llvm-project/pull/96183 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
https://github.com/ftynse commented: I think @MaheshRavishankar should take a look at the interface implementation details. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
https://github.com/ftynse edited https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2760,6 +2760,89 @@ LogicalResult WinogradFilterTransformOp::verify() { return success(); } +SmallVector +WinogradFilterTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + Value zero = builder.create(loc, 0); + Value one = builder.create(loc, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zero; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = one; + } + return loopBounds; +} + +SmallVector +WinogradFilterTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +Value getValueFromOpFoldResult(OpFoldResult opFoldResult, OpBuilder &builder, + Location loc) { + if (auto val = opFoldResult.dyn_cast()) { +return val; + } else if (auto attr = opFoldResult.dyn_cast()) { +auto intAttr = cast(attr); +return builder.create(loc, intAttr); + } ftynse wrote: I suspect this might already exist somewhere in the arith dialect. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2638,4 +2638,41 @@ def WinogradConv2DOp : Op { + let description = [{ +Decompose winograd operators. It will convert filter, input and output +transform operators into a combination of scf, tensor, and linalg ftynse wrote: Nit: operations https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2760,6 +2760,89 @@ LogicalResult WinogradFilterTransformOp::verify() { return success(); } +SmallVector +WinogradFilterTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + Value zero = builder.create(loc, 0); + Value one = builder.create(loc, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zero; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = one; + } + return loopBounds; +} + +SmallVector +WinogradFilterTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +Value getValueFromOpFoldResult(OpFoldResult opFoldResult, OpBuilder &builder, + Location loc) { + if (auto val = opFoldResult.dyn_cast()) { +return val; + } else if (auto attr = opFoldResult.dyn_cast()) { +auto intAttr = cast(attr); +return builder.create(loc, intAttr); + } + // This should never happen if OpFoldResult is correctly formed. ftynse wrote: Then this should be an assertion. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2760,6 +2760,89 @@ LogicalResult WinogradFilterTransformOp::verify() { return success(); } +SmallVector +WinogradFilterTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + Value zero = builder.create(loc, 0); + Value one = builder.create(loc, 1); ftynse wrote: IIRC, `Range` contains list of `OpFoldResult`, meaning we can put attributes there and not materialize operations for these constants. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][Transforms][NFC] Dialect Conversion: Move argument materialization logic (PR #96329)
https://github.com/ftynse approved this pull request. https://github.com/llvm/llvm-project/pull/96329 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2810,9 +2819,117 @@ LogicalResult WinogradInputTransformOp::verify() { if (failed(verifyCompatibleShape(expectedOutputShape, outputShape))) { return emitOpError("the output shape is not expected"); } + return success(); } +SmallVector +WinogradInputTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + auto indexType = builder.getIndexType(); + auto zeroAttr = builder.getIntegerAttr(indexType, 0); + auto oneAttr = builder.getIntegerAttr(indexType, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zeroAttr; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = oneAttr; + } + return loopBounds; +} + +SmallVector +WinogradInputTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +LogicalResult WinogradInputTransformOp::getResultTilePosition( +OpBuilder &builder, unsigned resultNumber, ArrayRef offsets, +ArrayRef sizes, SmallVector &resultOffsets, +SmallVector &resultSizes) { + auto zeroAttr = builder.getI64IntegerAttr(0); + auto oneAttr = builder.getI64IntegerAttr(1); + + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(offsets[2]); + resultOffsets.push_back(offsets[3]); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultSizes.push_back(sizes[0]); + resultSizes.push_back(sizes[1]); + resultSizes.push_back(oneAttr); + resultSizes.push_back(oneAttr); + resultSizes.push_back(sizes[4]); + resultSizes.push_back(sizes[5]); + + return success(); +} + +FailureOr +WinogradInputTransformOp::getTiledImplementation(OpBuilder &builder, + ArrayRef offsets, + ArrayRef sizes) { + auto oneAttr = builder.getI64IntegerAttr(1); + auto zeroAttr = builder.getI64IntegerAttr(0); + Value input = getInput(); + auto inputType = cast(input.getType()); + auto inputShape = inputType.getShape(); ftynse wrote: Please expand `auto` unless the type is obvious from statement-level context (builders on the RHS are fine, but I don't remember what `getShape` returns as a type). https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2810,9 +2819,117 @@ LogicalResult WinogradInputTransformOp::verify() { if (failed(verifyCompatibleShape(expectedOutputShape, outputShape))) { return emitOpError("the output shape is not expected"); } + return success(); } +SmallVector +WinogradInputTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + auto indexType = builder.getIndexType(); + auto zeroAttr = builder.getIntegerAttr(indexType, 0); + auto oneAttr = builder.getIntegerAttr(indexType, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zeroAttr; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = oneAttr; + } + return loopBounds; +} + +SmallVector +WinogradInputTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +LogicalResult WinogradInputTransformOp::getResultTilePosition( +OpBuilder &builder, unsigned resultNumber, ArrayRef offsets, +ArrayRef sizes, SmallVector &resultOffsets, +SmallVector &resultSizes) { + auto zeroAttr = builder.getI64IntegerAttr(0); + auto oneAttr = builder.getI64IntegerAttr(1); + + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(offsets[2]); + resultOffsets.push_back(offsets[3]); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultSizes.push_back(sizes[0]); + resultSizes.push_back(sizes[1]); + resultSizes.push_back(oneAttr); + resultSizes.push_back(oneAttr); + resultSizes.push_back(sizes[4]); + resultSizes.push_back(sizes[5]); ftynse wrote: Nit: something like `resultOffsets.append({zeroAttr, zeroAttr, offsets[2], offsets[3], zeroAttr, zeroAttr})` may be more readable. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
https://github.com/ftynse edited https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2810,9 +2819,117 @@ LogicalResult WinogradInputTransformOp::verify() { if (failed(verifyCompatibleShape(expectedOutputShape, outputShape))) { return emitOpError("the output shape is not expected"); } + return success(); } +SmallVector +WinogradInputTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + auto indexType = builder.getIndexType(); + auto zeroAttr = builder.getIntegerAttr(indexType, 0); + auto oneAttr = builder.getIntegerAttr(indexType, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zeroAttr; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = oneAttr; + } + return loopBounds; +} + +SmallVector +WinogradInputTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +LogicalResult WinogradInputTransformOp::getResultTilePosition( +OpBuilder &builder, unsigned resultNumber, ArrayRef offsets, +ArrayRef sizes, SmallVector &resultOffsets, +SmallVector &resultSizes) { + auto zeroAttr = builder.getI64IntegerAttr(0); + auto oneAttr = builder.getI64IntegerAttr(1); + + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(offsets[2]); + resultOffsets.push_back(offsets[3]); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultSizes.push_back(sizes[0]); + resultSizes.push_back(sizes[1]); + resultSizes.push_back(oneAttr); + resultSizes.push_back(oneAttr); + resultSizes.push_back(sizes[4]); + resultSizes.push_back(sizes[5]); + + return success(); +} + +FailureOr +WinogradInputTransformOp::getTiledImplementation(OpBuilder &builder, + ArrayRef offsets, + ArrayRef sizes) { + auto oneAttr = builder.getI64IntegerAttr(1); + auto zeroAttr = builder.getI64IntegerAttr(0); + Value input = getInput(); + auto inputType = cast(input.getType()); + auto inputShape = inputType.getShape(); + int64_t inputH = inputShape[1]; + int64_t inputW = inputShape[2]; + int64_t m = getM(); + int64_t r = getR(); + int64_t alpha = m + r - 1; + int64_t alphaH = inputH != 1 ? alpha : 1; + int64_t alphaW = inputW != 1 ? alpha : 1; + auto alphaHAttr = builder.getI64IntegerAttr(alphaH); + auto alphaWAttr = builder.getI64IntegerAttr(alphaW); + + Location loc = getLoc(); + SmallVector tiledOperands; + SmallVector sliceOffsets, sliceSizes; + + auto context = builder.getContext(); + auto affineMap = + AffineMap::get(1, 0, {builder.getAffineDimExpr(0) * m}, context); + Value mappedOffset1 = builder.create( + loc, affineMap, getValueFromOpFoldResult(offsets[2], builder, loc)); + Value mappedOffset2 = builder.create( + loc, affineMap, getValueFromOpFoldResult(offsets[3], builder, loc)); + + sliceOffsets.push_back(zeroAttr); + sliceOffsets.push_back(mappedOffset1); + sliceOffsets.push_back(mappedOffset2); + sliceOffsets.push_back(zeroAttr); + sliceSizes.push_back(sizes[4]); + sliceSizes.push_back(alphaHAttr); + sliceSizes.push_back(alphaWAttr); + sliceSizes.push_back(sizes[5]); + SmallVector inputStrides(4, oneAttr); + tiledOperands.emplace_back(builder.create( + loc, getInput(), sliceOffsets, sliceSizes, inputStrides)); + + sliceOffsets.clear(); + sliceSizes.clear(); ftynse wrote: I'd rather declare new vectors for this. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2810,9 +2819,117 @@ LogicalResult WinogradInputTransformOp::verify() { if (failed(verifyCompatibleShape(expectedOutputShape, outputShape))) { return emitOpError("the output shape is not expected"); } + return success(); } +SmallVector +WinogradInputTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + auto indexType = builder.getIndexType(); + auto zeroAttr = builder.getIntegerAttr(indexType, 0); + auto oneAttr = builder.getIntegerAttr(indexType, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zeroAttr; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = oneAttr; + } + return loopBounds; +} + +SmallVector +WinogradInputTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +LogicalResult WinogradInputTransformOp::getResultTilePosition( +OpBuilder &builder, unsigned resultNumber, ArrayRef offsets, +ArrayRef sizes, SmallVector &resultOffsets, +SmallVector &resultSizes) { + auto zeroAttr = builder.getI64IntegerAttr(0); + auto oneAttr = builder.getI64IntegerAttr(1); + + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(offsets[2]); + resultOffsets.push_back(offsets[3]); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultSizes.push_back(sizes[0]); + resultSizes.push_back(sizes[1]); + resultSizes.push_back(oneAttr); + resultSizes.push_back(oneAttr); + resultSizes.push_back(sizes[4]); + resultSizes.push_back(sizes[5]); + + return success(); +} + +FailureOr +WinogradInputTransformOp::getTiledImplementation(OpBuilder &builder, + ArrayRef offsets, + ArrayRef sizes) { + auto oneAttr = builder.getI64IntegerAttr(1); + auto zeroAttr = builder.getI64IntegerAttr(0); + Value input = getInput(); + auto inputType = cast(input.getType()); + auto inputShape = inputType.getShape(); + int64_t inputH = inputShape[1]; + int64_t inputW = inputShape[2]; + int64_t m = getM(); + int64_t r = getR(); + int64_t alpha = m + r - 1; + int64_t alphaH = inputH != 1 ? alpha : 1; + int64_t alphaW = inputW != 1 ? alpha : 1; + auto alphaHAttr = builder.getI64IntegerAttr(alphaH); + auto alphaWAttr = builder.getI64IntegerAttr(alphaW); + + Location loc = getLoc(); + SmallVector tiledOperands; + SmallVector sliceOffsets, sliceSizes; + + auto context = builder.getContext(); + auto affineMap = + AffineMap::get(1, 0, {builder.getAffineDimExpr(0) * m}, context); + Value mappedOffset1 = builder.create( + loc, affineMap, getValueFromOpFoldResult(offsets[2], builder, loc)); + Value mappedOffset2 = builder.create( + loc, affineMap, getValueFromOpFoldResult(offsets[3], builder, loc)); + + sliceOffsets.push_back(zeroAttr); + sliceOffsets.push_back(mappedOffset1); + sliceOffsets.push_back(mappedOffset2); + sliceOffsets.push_back(zeroAttr); + sliceSizes.push_back(sizes[4]); + sliceSizes.push_back(alphaHAttr); + sliceSizes.push_back(alphaWAttr); + sliceSizes.push_back(sizes[5]); + SmallVector inputStrides(4, oneAttr); + tiledOperands.emplace_back(builder.create( + loc, getInput(), sliceOffsets, sliceSizes, inputStrides)); + + sliceOffsets.clear(); + sliceSizes.clear(); + if (failed(getResultTilePosition(builder, 1, offsets, sizes, sliceOffsets, + sliceSizes))) +return failure(); + + SmallVector outputStrides(6, oneAttr); + tiledOperands.emplace_back(builder.create( + loc, getOutput(), sliceOffsets, sliceSizes, outputStrides)); + + SmallVector resultTypes; ftynse wrote: ```suggestion SmallVector resultTypes; ``` https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
https://github.com/ftynse commented: Looks okay to me in general. Something went wrong with rebases so I see code that doesn't belong to this change. Let me know when you merged the bases and I can click-approve this one. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2776,6 +2776,15 @@ LogicalResult WinogradFilterTransformOp::verify() { // WinogradInputTransformOp //===--===// +Value getValueFromOpFoldResult(OpFoldResult opFoldResult, OpBuilder &builder, + Location loc) { + if (auto attr = opFoldResult.dyn_cast()) { +auto intAttr = cast(attr); +return builder.create(loc, intAttr); + } + return opFoldResult.get(); +} ftynse wrote: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Dialect/Arith/Utils/Utils.h#L68-L72 it already exists https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][linalg] Implement TilingInterface for winograd operators (PR #96184)
@@ -2810,9 +2819,117 @@ LogicalResult WinogradInputTransformOp::verify() { if (failed(verifyCompatibleShape(expectedOutputShape, outputShape))) { return emitOpError("the output shape is not expected"); } + return success(); } +SmallVector +WinogradInputTransformOp::getIterationDomain(OpBuilder &builder) { + Location loc = getLoc(); + auto indexType = builder.getIndexType(); + auto zeroAttr = builder.getIntegerAttr(indexType, 0); + auto oneAttr = builder.getIntegerAttr(indexType, 1); + Value output = getOutput(); + SmallVector loopBounds(6); + for (unsigned dim = 0; dim < 6; ++dim) { +loopBounds[dim].offset = zeroAttr; +loopBounds[dim].size = getDimValue(builder, loc, output, dim); +loopBounds[dim].stride = oneAttr; + } + return loopBounds; +} + +SmallVector +WinogradInputTransformOp::getLoopIteratorTypes() { + SmallVector iteratorTypes(6, + utils::IteratorType::parallel); + return iteratorTypes; +} + +LogicalResult WinogradInputTransformOp::getResultTilePosition( +OpBuilder &builder, unsigned resultNumber, ArrayRef offsets, +ArrayRef sizes, SmallVector &resultOffsets, +SmallVector &resultSizes) { + auto zeroAttr = builder.getI64IntegerAttr(0); + auto oneAttr = builder.getI64IntegerAttr(1); + + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(offsets[2]); + resultOffsets.push_back(offsets[3]); + resultOffsets.push_back(zeroAttr); + resultOffsets.push_back(zeroAttr); + resultSizes.push_back(sizes[0]); + resultSizes.push_back(sizes[1]); + resultSizes.push_back(oneAttr); + resultSizes.push_back(oneAttr); + resultSizes.push_back(sizes[4]); + resultSizes.push_back(sizes[5]); + + return success(); +} + +FailureOr +WinogradInputTransformOp::getTiledImplementation(OpBuilder &builder, + ArrayRef offsets, + ArrayRef sizes) { + auto oneAttr = builder.getI64IntegerAttr(1); + auto zeroAttr = builder.getI64IntegerAttr(0); + Value input = getInput(); + auto inputType = cast(input.getType()); + auto inputShape = inputType.getShape(); ftynse wrote: Here and below. https://github.com/llvm/llvm-project/pull/96184 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][Transform] `apply_conversion_patterns`: Update handles (PR #83950)
@@ -632,7 +663,11 @@ LogicalResult transform::ApplyConversionPatternsOp::verify() { void transform::ApplyConversionPatternsOp::getEffects( SmallVectorImpl &effects) { - transform::consumesHandle(getTarget(), effects); + if (!getPreserveHandles()) { +transform::consumesHandle(getTarget(), effects); + } else { +transform::onlyReadsHandle(getTarget(), effects); + } ftynse wrote: Nit: I don't recall if dialect conversion could rewrite the top-level op or not. If it can, it may need to still consume the handle... https://github.com/llvm/llvm-project/pull/83950 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][Transform] `apply_conversion_patterns`: Update handles (PR #83950)
https://github.com/ftynse edited https://github.com/llvm/llvm-project/pull/83950 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][Transform] `apply_conversion_patterns`: Update handles (PR #83950)
https://github.com/ftynse approved this pull request. https://github.com/llvm/llvm-project/pull/83950 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][Transform] `apply_conversion_patterns`: Update handles (PR #83950)
@@ -190,19 +190,29 @@ def ApplyConversionPatternsOp : TransformDialectOp<"apply_conversion_patterns", The `legal_ops`, `illegal_ops`, `legal_dialects`, `illegal_dialects` attributes specify the conversion target. -This transform consumes the `target` handle and modifies the payload. It -does not produce any handles. +This transform modifies the payload. By default, it consumes the `target` +handle. It does not produce any handles. + +If the `preserve_handles` attribute is set, this transform does not consume +the `target` handle and instead updates handles based on notifications from +a tracking listener that is attached to the dialect conversion, similar to +`transform.apply_patterns`. Only replacements via `RewriterBase::replaceOp` +or `replaceOpWithNewOp` are considered "payload op replacements". In +contrast to `transform.apply_patterns`, we allow replacement ops even if the ftynse wrote: Nit: could you provide the rationale as to why op name change is allowed here? Presumably because conversion is expected to intentionally change names to another dialect. https://github.com/llvm/llvm-project/pull/83950 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] release/18.x: [MLIR] [Transforms] Let `transform.structured.convert_to_loops` return handles to loops (#83984) (PR #85942)
ftynse wrote: https://github.com/llvm/llvm-project/commit/0597644a6466ae9148b0b41cb8f95d5022e045c2 looks like a bugfix, but https://github.com/llvm/llvm-project/commit/47bc565ca7990a2de20af4030baf08ac62739aca is a arguably a new feature and likely should not be backported. What is the reason for backporting the latter? https://github.com/llvm/llvm-project/pull/85942 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] release/18.x: [mlir][transform] replace original op to loop ops (#83537) (PR #87080)
https://github.com/ftynse approved this pull request. https://github.com/llvm/llvm-project/pull/87080 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [MLIR] Add apply_patterns.vector.arm_sve.lower_contraction TD Op (PR #140572)
@@ -93,3 +99,15 @@ func.func @test_vector_contract_to_usmmla( return %2 : vector<4x[4]xi32> } + +module attributes {transform.with_named_sequence} { + transform.named_sequence @__transform_main(%module: !transform.any_op {transform.readonly}) { +%func = transform.structured.match ops{["func.func"]} in %module : (!transform.any_op) -> !transform.op<"func.func"> + +transform.apply_patterns to %func { + transform.apply_patterns.vector.arm_sve.lower_contraction +} : !transform.op<"func.func"> + +transform.yield + } +} ftynse wrote: Nit: trailing newline please (may require configuring your editor appropriately). https://github.com/llvm/llvm-project/pull/140572 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [MLIR] Add apply_patterns.vector.arm_sve.lower_contraction TD Op (PR #140572)
https://github.com/ftynse approved this pull request. https://github.com/llvm/llvm-project/pull/140572 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir] NFC - refactor id builder and avoid leaking impl details (PR #146922)
https://github.com/ftynse approved this pull request. https://github.com/llvm/llvm-project/pull/146922 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
@@ -744,8 +758,7 @@ static DiagnosedSilenceableFailure getThreadIdBuilder(std::optional transformOp, scf::ForallOp forallOp, ArrayRef blockSizes, int64_t warpSize, GpuIdBuilder &gpuIdBuilder) { - auto mappingAttr = cast( - forallOp.getMapping()->getValue().front()); + auto mappingAttr = forallOp.getDeviceMappingAttrs().front(); ftynse wrote: Nit: now that there's no more cast on the RHS, please expand `auto`. https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
@@ -78,7 +78,8 @@ struct GpuIdBuilder { /// If `useLinearMapping` is true, the `idBuilder` method returns nD values /// used for indexing rewrites as well as 1D sizes for predicate generation. struct GpuBlockIdBuilder : public GpuIdBuilder { - GpuBlockIdBuilder(MLIRContext *ctx, bool useLinearMapping = false); ftynse wrote: Could you please the comments above to reflect this new argument? Here and below. https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
@@ -60,8 +60,51 @@ def DeviceMappingAttrInterface : AttrInterface<"DeviceMappingAttrInterface"> { ]; } +def DeviceMaskingAttrInterface : AttrInterface<"DeviceMaskingAttrInterface"> { + let cppNamespace = "::mlir"; + let description = [{ +Attribute interface describing how to filter the processing units that a +region is mapped to. + +A popcount can be applied to determine the logical linear index that a +physical processing unit is responsible for. + }]; + + let methods = [ +InterfaceMethod< + /*desc=*/[{ +Return the logical active id for a given physical id. +Expects a physicalLinearMappingId of I64Type. + }], + /*retTy=*/"Value", + /*methodName=*/"getLogicalLinearMappingId", + /*args=*/(ins "OpBuilder&":$builder, "Value":$physicalLinearMappingId) +>, +InterfaceMethod< + /*desc=*/[{ +Return the dynamic condition determining whether a given physical id is +active under the mask. +Expects a physicalLinearMappingId of I64Type. + }], + /*retTy=*/"Value", + /*methodName=*/"getIsActiveIdPredicate", + /*args=*/(ins "OpBuilder&":$builder, "Value":$physicalLinearMappingId) +>, +InterfaceMethod< + /*desc=*/[{ +Return the maximal number of pysical ids supported. ftynse wrote: ```suggestion Return the maximal number of physical ids supported. ``` https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
@@ -60,8 +60,51 @@ def DeviceMappingAttrInterface : AttrInterface<"DeviceMappingAttrInterface"> { ]; } +def DeviceMaskingAttrInterface : AttrInterface<"DeviceMaskingAttrInterface"> { + let cppNamespace = "::mlir"; + let description = [{ +Attribute interface describing how to filter the processing units that a +region is mapped to. + +A popcount can be applied to determine the logical linear index that a +physical processing unit is responsible for. + }]; + + let methods = [ +InterfaceMethod< + /*desc=*/[{ +Return the logical active id for a given physical id. +Expects a physicalLinearMappingId of I64Type. + }], + /*retTy=*/"Value", + /*methodName=*/"getLogicalLinearMappingId", ftynse wrote: Optional naming nit: `bulidFoo` or `createFoo` instead of `getFoo` will make it clearer that some IR is being constructed. https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
@@ -60,8 +60,51 @@ def DeviceMappingAttrInterface : AttrInterface<"DeviceMappingAttrInterface"> { ]; } +def DeviceMaskingAttrInterface : AttrInterface<"DeviceMaskingAttrInterface"> { + let cppNamespace = "::mlir"; + let description = [{ +Attribute interface describing how to filter the processing units that a +region is mapped to. + +A popcount can be applied to determine the logical linear index that a +physical processing unit is responsible for. + }]; ftynse wrote: Could you please document what is understood by physical and logical ID here and how either of those can be linear. https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [mlir] [mlir][SCF][GPU] Add DeviceMaskingAttrInterface support to scf::Foral… (PR #146943)
https://github.com/ftynse edited https://github.com/llvm/llvm-project/pull/146943 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits