Move softmax matcher and ErrorCheckingTrackingListener out of iree-dialects (#24466) (#24543)
Closes #24466 (retire the
`llvm-external-projects/iree-dialects`
dependency). Relocates the last two pieces of code that still depended
on the NFC directory. Finishing Tasks 1 & 4.
- **[GlobalOpt] Reimplements the softmax matcher within
`GlobalOptimization/`. Adds `arith.maximumf` support to account for SHLO decompositions.
- **[Codegen] Move ErrorCheckingTrackingListener** into
`Codegen/Common/` and de-register `StructuredTransformOpsExtension` from
`CommonDialectRegistration` and `Interfaces`. Continuation of #24500.
- Removes llvm-external-projects/iree-dialects as a whole
## Testing
Built and lit tested locally on Windows 11 + MSVC 14.44 (VS 2022
Community), Ninja, CMake 3.29, Release with assertions,
`IREE_TARGET_BACKEND_LLVM_CPU=ON`. All changed files compile cleanly.
The softmax lit test
`compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir`
passed. all three variants (`@softmax`, `@softmax_no_rcp`,
`@softmax_broadcast`) match correctly through the relocated
`makeSoftmaxMatcher`.
---------
Signed-off-by: Han || Alex <36247722+Alex-Wengg@users.noreply.github.com>
Signed-off-by: Alex-Wengg <hanweng9@gmail.com>
diff --git a/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py b/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
index bebad4e..297e05f 100644
--- a/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
+++ b/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
@@ -27,10 +27,6 @@
f"{iree_core_repo}//compiler/src/iree/compiler/API:CAPI": [
"IREECompilerCAPILib"
],
- # IREE llvm-external-projects
- f"{iree_core_repo}//llvm-external-projects/iree-dialects:CAPI": [
- "IREEDialectsCAPI"
- ],
# Disable all hard-coded codegen targets (they are expanded dynamically
# in CMake).
"@llvm-project//llvm:AArch64AsmParser": ["IREELLVMCPUTargetDeps"],
diff --git a/compiler/plugins/target/LLVMCPU/BUILD.bazel b/compiler/plugins/target/LLVMCPU/BUILD.bazel
index c2bb725..61f18a0 100644
--- a/compiler/plugins/target/LLVMCPU/BUILD.bazel
+++ b/compiler/plugins/target/LLVMCPU/BUILD.bazel
@@ -48,7 +48,6 @@
"//compiler/src/iree/compiler/Dialect/Util/IR",
"//compiler/src/iree/compiler/PluginAPI",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:AArch64AsmParser",
"@llvm-project//llvm:AArch64CodeGen",
"@llvm-project//llvm:ARMAsmParser",
diff --git a/compiler/plugins/target/LLVMCPU/CMakeLists.txt b/compiler/plugins/target/LLVMCPU/CMakeLists.txt
index 345f389..1b7b043 100644
--- a/compiler/plugins/target/LLVMCPU/CMakeLists.txt
+++ b/compiler/plugins/target/LLVMCPU/CMakeLists.txt
@@ -31,7 +31,6 @@
::LinkerTool
::StaticLibraryGenerator
IREELLVMCPUTargetDeps
- IREELinalgTransformDialect
LLVMAnalysis
LLVMBitReader
LLVMBitWriter
diff --git a/compiler/src/iree/compiler/API/BUILD.bazel b/compiler/src/iree/compiler/API/BUILD.bazel
index 9ca3ea7..f10c922 100644
--- a/compiler/src/iree/compiler/API/BUILD.bazel
+++ b/compiler/src/iree/compiler/API/BUILD.bazel
@@ -37,7 +37,6 @@
"//compiler/src/iree/compiler/API/Internal:IREEOptToolEntryPoint",
"//compiler/src/iree/compiler/API/Internal:IREEReduceToolEntryPoint",
"//compiler/src/iree/compiler/API/Internal:LLDToolEntryPoint",
- "//llvm-external-projects/iree-dialects:CAPI",
"@llvm-project//mlir:CAPIAMDGPU",
"@llvm-project//mlir:CAPIDebug",
"@llvm-project//mlir:CAPIGPU",
diff --git a/compiler/src/iree/compiler/API/CMakeLists.txt b/compiler/src/iree/compiler/API/CMakeLists.txt
index 8d76da8..d0a0a69 100644
--- a/compiler/src/iree/compiler/API/CMakeLists.txt
+++ b/compiler/src/iree/compiler/API/CMakeLists.txt
@@ -14,7 +14,6 @@
NAME
StaticImpl
DEPS
- IREEDialectsCAPI
MLIRCAPIAMDGPU
MLIRCAPIDebug
MLIRCAPIExportSMTLIB
@@ -82,7 +81,6 @@
iree_compiler_API_Internal_IREEOptToolEntryPoint.objects
iree_compiler_API_Internal_IREEReduceToolEntryPoint.objects
iree_compiler_API_Internal_LLDToolEntryPoint.objects
- obj.IREEDialectsCAPI
obj.MLIRCAPIAMDGPU
obj.MLIRCAPIDebug
obj.MLIRCAPIExportSMTLIB
diff --git a/compiler/src/iree/compiler/API/api_exports.c b/compiler/src/iree/compiler/API/api_exports.c
index 7542886..f672810 100644
--- a/compiler/src/iree/compiler/API/api_exports.c
+++ b/compiler/src/iree/compiler/API/api_exports.c
@@ -154,7 +154,6 @@
extern void ireeMlirLspServerRunMain();
extern void ireeOptRunMain();
extern void ireeReduceRunMain();
-extern void ireeRegisterTransformExtensions();
extern void mlirAffineAddExprGet();
extern void mlirAffineBinaryOpExprGetLHS();
extern void mlirAffineBinaryOpExprGetRHS();
@@ -1331,7 +1330,6 @@
x += (uintptr_t)&ireeMlirLspServerRunMain;
x += (uintptr_t)&ireeOptRunMain;
x += (uintptr_t)&ireeReduceRunMain;
- x += (uintptr_t)&ireeRegisterTransformExtensions;
x += (uintptr_t)&mlirAffineAddExprGet;
x += (uintptr_t)&mlirAffineBinaryOpExprGetLHS;
x += (uintptr_t)&mlirAffineBinaryOpExprGetRHS;
diff --git a/compiler/src/iree/compiler/API/api_exports.def b/compiler/src/iree/compiler/API/api_exports.def
index eb7fa77..d859549 100644
--- a/compiler/src/iree/compiler/API/api_exports.def
+++ b/compiler/src/iree/compiler/API/api_exports.def
@@ -144,7 +144,6 @@
ireeMlirLspServerRunMain
ireeOptRunMain
ireeReduceRunMain
- ireeRegisterTransformExtensions
mlirAffineAddExprGet
mlirAffineBinaryOpExprGetLHS
mlirAffineBinaryOpExprGetRHS
diff --git a/compiler/src/iree/compiler/API/api_exports.ld b/compiler/src/iree/compiler/API/api_exports.ld
index d879b7c..564618e 100644
--- a/compiler/src/iree/compiler/API/api_exports.ld
+++ b/compiler/src/iree/compiler/API/api_exports.ld
@@ -145,7 +145,6 @@
ireeMlirLspServerRunMain;
ireeOptRunMain;
ireeReduceRunMain;
- ireeRegisterTransformExtensions;
mlirAffineAddExprGet;
mlirAffineBinaryOpExprGetLHS;
mlirAffineBinaryOpExprGetRHS;
diff --git a/compiler/src/iree/compiler/API/api_exports.macos.lst b/compiler/src/iree/compiler/API/api_exports.macos.lst
index b65bd5c..b03167c 100644
--- a/compiler/src/iree/compiler/API/api_exports.macos.lst
+++ b/compiler/src/iree/compiler/API/api_exports.macos.lst
@@ -143,7 +143,6 @@
_ireeMlirLspServerRunMain
_ireeOptRunMain
_ireeReduceRunMain
-_ireeRegisterTransformExtensions
_mlirAffineAddExprGet
_mlirAffineBinaryOpExprGetLHS
_mlirAffineBinaryOpExprGetRHS
diff --git a/compiler/src/iree/compiler/API/generate_exports.py b/compiler/src/iree/compiler/API/generate_exports.py
index 31b6bd0..05d79fe 100755
--- a/compiler/src/iree/compiler/API/generate_exports.py
+++ b/compiler/src/iree/compiler/API/generate_exports.py
@@ -67,10 +67,6 @@
"Dialect/PDL.h",
]
-IREE_DIALECTS_HEADER_FILES = [
- "Dialects.h",
-]
-
IREE_COMPILER_DIALECTS_HEADER_FILES = [
"iree_codegen.h",
"iree_gpu.h",
@@ -101,16 +97,6 @@
for local_name in LOCAL_HEADER_FILES:
export_symbols.extend(collect_header_exports(api_root / local_name))
- # Collect symbols from iree-dialects header files.
- for local_name in IREE_DIALECTS_HEADER_FILES:
- export_symbols.extend(
- collect_header_exports(
- repo_root
- / "llvm-external-projects/iree-dialects/include/iree-dialects-c"
- / local_name
- )
- )
-
# Collect symbols from iree compiler dialect header files.
for local_name in IREE_COMPILER_DIALECTS_HEADER_FILES:
export_symbols.extend(
diff --git a/compiler/src/iree/compiler/Codegen/Common/BUILD.bazel b/compiler/src/iree/compiler/Codegen/Common/BUILD.bazel
index 81167e5..fa6dd7e 100644
--- a/compiler/src/iree/compiler/Codegen/Common/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/Common/BUILD.bazel
@@ -103,6 +103,7 @@
"EncodingUtils.cpp",
"EraseDeadAllocAndStores.cpp",
"EraseHALDescriptorTypeFromMemRef.cpp",
+ "ErrorCheckingTrackingListener.cpp",
"FastMathPatterns.cpp",
"FissionTransferOpsInControlFlow.cpp",
"FlattenMemRefSubspan.cpp",
@@ -190,6 +191,7 @@
"CombineLayoutTransformation.h",
"EmulateNarrowType.h",
"EncodingUtils.h",
+ "ErrorCheckingTrackingListener.h",
"FastMathPatterns.h",
"PassUtils.h",
"Passes.h",
@@ -234,7 +236,6 @@
"//compiler/src/iree/compiler/Dialect/Util/IR",
"//compiler/src/iree/compiler/Dialect/Util/Transforms",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Core",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AMDGPUDialect",
@@ -332,7 +333,6 @@
"//compiler/src/iree/compiler/Dialect/LinalgExt/IR",
"//compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions:LinalgExtExtensions",
"//compiler/src/iree/compiler/Dialect/TensorExt/IR",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"//compiler/src/iree/compiler/Codegen/Dialect/VectorExt/IR:IREEVectorExtDialect",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:AffineUtils",
@@ -377,7 +377,6 @@
"@llvm-project//mlir:Support",
"@llvm-project//mlir:DialectUtils",
# TransformExtensions (needed for registration in the pass)
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
"//compiler/src/iree/compiler/Codegen/Common/TransformExtensions:CommonExtensions",
"//compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions:LLVMCPUExtensions",
"//compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions:LLVMGPUExtensions",
diff --git a/compiler/src/iree/compiler/Codegen/Common/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/Common/CMakeLists.txt
index a3f5d46..0b38a52 100644
--- a/compiler/src/iree/compiler/Codegen/Common/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/Common/CMakeLists.txt
@@ -56,6 +56,7 @@
"CombineLayoutTransformation.h"
"EmulateNarrowType.h"
"EncodingUtils.h"
+ "ErrorCheckingTrackingListener.h"
"FastMathPatterns.h"
"PassUtils.h"
"Passes.h"
@@ -96,6 +97,7 @@
"EncodingUtils.cpp"
"EraseDeadAllocAndStores.cpp"
"EraseHALDescriptorTypeFromMemRef.cpp"
+ "ErrorCheckingTrackingListener.cpp"
"FastMathPatterns.cpp"
"FissionTransferOpsInControlFlow.cpp"
"FlattenMemRefSubspan.cpp"
@@ -180,7 +182,6 @@
DEPS
::PassHeaders
::PassesIncGen
- IREELinalgTransformDialect
LLVMCore
LLVMSupport
MLIRAMDGPUDialect
@@ -287,8 +288,6 @@
::Common
::PassHeaders
::PassesIncGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAMDGPUTransforms
MLIRAffineDialect
diff --git a/compiler/src/iree/compiler/Codegen/Common/CommonDialectRegistration.cpp b/compiler/src/iree/compiler/Codegen/Common/CommonDialectRegistration.cpp
index d718749..69733a6 100644
--- a/compiler/src/iree/compiler/Codegen/Common/CommonDialectRegistration.cpp
+++ b/compiler/src/iree/compiler/Codegen/Common/CommonDialectRegistration.cpp
@@ -4,7 +4,6 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
#include "iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.h"
#include "iree/compiler/Codegen/Dialect/Codegen/IR/IREECodegenDialect.h"
#include "iree/compiler/Codegen/Dialect/GPU/IR/IREEGPUDialect.h"
@@ -97,8 +96,7 @@
vector::registerBufferizableOpInterfaceExternalModels(registry);
registry.addExtensions<
- mlir::iree_compiler::IREE::LinalgExt::LinalgExtTransformOpsExtension,
- transform_ext::StructuredTransformOpsExtension>();
+ mlir::iree_compiler::IREE::LinalgExt::LinalgExtTransformOpsExtension>();
iree_compiler::registerTransformDialectCommonExtension(registry);
iree_compiler::registerTransformDialectLLVMCPUExtension(registry);
iree_compiler::registerTransformDialectLLVMGPUExtension(registry);
diff --git a/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.cpp b/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.cpp
new file mode 100644
index 0000000..91285ec
--- /dev/null
+++ b/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.cpp
@@ -0,0 +1,40 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed 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
+
+#include "iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h"
+
+#include "llvm/Support/Debug.h"
+#include "mlir/Dialect/SCF/IR/SCF.h"
+
+#define DEBUG_TYPE "iree-codegen-error-checking-tracking-listener"
+#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE "]: ")
+
+namespace mlir::iree_compiler {
+
+void ErrorCheckingTrackingListener::notifyPayloadReplacementNotFound(
+ Operation *op, ValueRange values, DiagnosedSilenceableFailure &&diag) {
+ // Certain ops can dropped safely.
+ if (isa<scf::ForOp>(op)) {
+ LLVM_DEBUG(DBGS() << "Silently dropping scf.for op mapping\n");
+ return;
+ }
+
+ SmallVector<Diagnostic> diags;
+ diag.takeDiagnostics(diags);
+ if (!status.succeeded()) {
+ status.takeDiagnostics(diags);
+ }
+ status = DiagnosedSilenceableFailure::silenceableFailure(std::move(diags));
+
+ status = emitSilenceableFailure(
+ getTransformOp(), "!!! tracking listener failed to find replacement op");
+ status.attachNote(op->getLoc()) << "replaced op";
+ for (Value v : values) {
+ status.attachNote(v.getLoc()) << "replacement value";
+ }
+}
+
+} // namespace mlir::iree_compiler
diff --git a/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h b/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h
new file mode 100644
index 0000000..35ea97d
--- /dev/null
+++ b/compiler/src/iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h
@@ -0,0 +1,48 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed 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 IREE_COMPILER_CODEGEN_COMMON_ERRORCHECKINGTRACKINGLISTENER_H_
+#define IREE_COMPILER_CODEGEN_COMMON_ERRORCHECKINGTRACKINGLISTENER_H_
+
+#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
+
+namespace mlir::iree_compiler {
+
+/// A tracking listener for tensor IR that checks for payload replacement
+/// errors.
+class ErrorCheckingTrackingListener : public transform::TrackingListener {
+public:
+ using transform::TrackingListener::TrackingListener;
+
+ ~ErrorCheckingTrackingListener() override {
+ assert(status.succeeded() && "must check listener error state");
+ }
+
+ /// Return "true" if this tracking listener had a failure.
+ bool failed() const { return !status.succeeded(); }
+
+ /// Check and return the current error state of this listener. In case of a
+ /// failure state, only the most recent error is returned. Afterwards, resets
+ /// the error state.
+ DiagnosedSilenceableFailure checkAndResetError() {
+ DiagnosedSilenceableFailure result(std::move(status));
+ status = DiagnosedSilenceableFailure::success();
+ return result;
+ }
+
+private:
+ void
+ notifyPayloadReplacementNotFound(Operation *op, ValueRange values,
+ DiagnosedSilenceableFailure &&diag) override;
+
+ /// The error state of this listener. "Success" indicates that no error
+ /// happened so far. Otherwise, the status contains the most recent error.
+ DiagnosedSilenceableFailure status = DiagnosedSilenceableFailure::success();
+};
+
+} // namespace mlir::iree_compiler
+
+#endif // IREE_COMPILER_CODEGEN_COMMON_ERRORCHECKINGTRACKINGLISTENER_H_
diff --git a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/BUILD.bazel
index 296f035..6601bda 100644
--- a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/BUILD.bazel
@@ -75,8 +75,6 @@
"//compiler/src/iree/compiler/Codegen/Utils",
"//compiler/src/iree/compiler/Dialect/HAL/IR",
"//compiler/src/iree/compiler/Dialect/LinalgExt/IR",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:AffineUtils",
diff --git a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CMakeLists.txt
index 2f91228..a98181a 100644
--- a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"CommonExtensionsOps.cpp.inc"
DEPS
::CommonExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAffineDialect
MLIRAffineUtils
diff --git a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.cpp b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.cpp
index 463f604..bb0eb1e 100644
--- a/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.cpp
+++ b/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.cpp
@@ -6,8 +6,7 @@
#include "CommonExtensions.h"
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
-#include "iree-dialects/Transforms/TransformMatchers.h"
+#include "iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h"
#include "iree/compiler/Codegen/Common/GPU/GPUPatterns.h"
#include "iree/compiler/Codegen/Common/GPU/GPUVectorDistribution.h"
#include "iree/compiler/Codegen/Common/GPU/Passes.h"
@@ -48,6 +47,7 @@
#include "mlir/Dialect/SCF/Utils/Utils.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Tensor/Transforms/Transforms.h"
+#include "mlir/Dialect/Transform/IR/TransformTypes.h"
#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
diff --git a/compiler/src/iree/compiler/Codegen/Interfaces/BUILD.bazel b/compiler/src/iree/compiler/Codegen/Interfaces/BUILD.bazel
index bcba86b..7ff9311 100644
--- a/compiler/src/iree/compiler/Codegen/Interfaces/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/Interfaces/BUILD.bazel
@@ -61,7 +61,6 @@
"//compiler/src/iree/compiler/Codegen/Dialect/PCF/ExternalInterfaces:ExternalModels",
"//compiler/src/iree/compiler/Codegen/ExternalInterfaces:ExternalModels",
"//compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions:LinalgExtExtensions",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:LinalgTransforms",
"@llvm-project//mlir:SideEffectInterfaces",
diff --git a/compiler/src/iree/compiler/Codegen/Interfaces/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/Interfaces/CMakeLists.txt
index c22bc95..646bba0 100644
--- a/compiler/src/iree/compiler/Codegen/Interfaces/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/Interfaces/CMakeLists.txt
@@ -25,7 +25,6 @@
::TensorMaskingOpInterface
::UKernelOpInterface
::VectorizableOpInterface
- IREELinalgTransformDialect
MLIRAMDGPUDialect
MLIRAffineDialect
MLIRAffineTransformOps
diff --git a/compiler/src/iree/compiler/Codegen/Interfaces/Interfaces.cpp b/compiler/src/iree/compiler/Codegen/Interfaces/Interfaces.cpp
index e21cde5..69483e8 100644
--- a/compiler/src/iree/compiler/Codegen/Interfaces/Interfaces.cpp
+++ b/compiler/src/iree/compiler/Codegen/Interfaces/Interfaces.cpp
@@ -6,6 +6,7 @@
#include "iree/compiler/Codegen/Interfaces/Interfaces.h"
+#include "iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.h"
#include "iree/compiler/Codegen/Dialect/GPU/ExternalInterfaces/Interfaces.h"
#include "iree/compiler/Codegen/Dialect/GPU/TransformExtensions/IREEGPUExtensions.h"
#include "iree/compiler/Codegen/Dialect/Map/ExternalInterfaces/Interfaces.h"
@@ -15,14 +16,8 @@
#include "iree/compiler/Codegen/Interfaces/HoistableRegionOpInterface.h"
#include "iree/compiler/Codegen/Interfaces/PartitionableLoopsInterface.h"
#include "iree/compiler/Codegen/Interfaces/ProcessorOpInterfaces.h"
-#include "iree/compiler/Codegen/Interfaces/VectorizableOpInterface.h"
-#include "mlir/Dialect/Linalg/IR/Linalg.h"
-#include "mlir/Interfaces/SideEffectInterfaces.h"
-// TODO: Remove this dependency once the transform dialect extensions
-// have a better registration mechanism.
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
-#include "iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.h"
#include "iree/compiler/Codegen/Interfaces/TensorMaskingOpInterface.h"
+#include "iree/compiler/Codegen/Interfaces/VectorizableOpInterface.h"
#include "iree/compiler/Codegen/LLVMCPU/TransformExtensions/LLVMCPUExtensions.h"
#include "iree/compiler/Codegen/LLVMGPU/TransformExtensions/LLVMGPUExtensions.h"
#include "iree/compiler/Dialect/LinalgExt/TransformExtensions/LinalgExtExtensionsOps.h"
@@ -33,6 +28,7 @@
#include "mlir/Dialect/GPU/IR/ValueBoundsOpInterfaceImpl.h"
#include "mlir/Dialect/GPU/TransformOps/GPUTransformOps.h"
#include "mlir/Dialect/GPU/Transforms/IndexedAccessOpInterfaceImpl.h"
+#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/Linalg/IR/ValueBoundsOpInterfaceImpl.h"
#include "mlir/Dialect/Linalg/TransformOps/DialectExtension.h"
#include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
@@ -50,6 +46,7 @@
#include "mlir/Dialect/Vector/TransformOps/VectorTransformOps.h"
#include "mlir/Dialect/Vector/Transforms/IndexedAccessOpInterfaceImpl.h"
#include "mlir/Dialect/Vector/Transforms/SubsetOpInterfaceImpl.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
namespace mlir::iree_compiler {
@@ -90,11 +87,8 @@
registerPCFExternalInterfaces(registry);
registerBufferizationInterfaces(registry);
registerTensorMaskingOpInterface(registry);
- // TODO: Remove this dependency once the transform dialect extensions
- // have a better registration mechanism.
// TODO: when warranted, move to its own file.
- registry.addExtensions<IREE::LinalgExt::LinalgExtTransformOpsExtension,
- transform_ext::StructuredTransformOpsExtension>();
+ registry.addExtensions<IREE::LinalgExt::LinalgExtTransformOpsExtension>();
registry.addExtension(+[](MLIRContext *ctx, linalg::LinalgDialect *dialect) {
linalg::GenericOp::attachInterface<LinalgGenericHoistableRegionModel>(*ctx);
});
diff --git a/compiler/src/iree/compiler/Codegen/LLVMCPU/BUILD.bazel b/compiler/src/iree/compiler/Codegen/LLVMCPU/BUILD.bazel
index a186358..c1e522d 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMCPU/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/LLVMCPU/BUILD.bazel
@@ -119,7 +119,6 @@
"//compiler/src/iree/compiler/Dialect/Util/Transforms",
"//compiler/src/iree/compiler/Transforms",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"//runtime/src/iree/schemas:cpu_data",
"//runtime/src/iree/schemas/instruments",
"@llvm-project//llvm:BinaryFormat",
diff --git a/compiler/src/iree/compiler/Codegen/LLVMCPU/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/LLVMCPU/CMakeLists.txt
index 5c0ccd3..1a5de09 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMCPU/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/LLVMCPU/CMakeLists.txt
@@ -84,7 +84,6 @@
DEPS
::PassHeaders
::PassesIncGen
- IREELinalgTransformDialect
LLVMBinaryFormat
LLVMSupport
LLVMTargetParser
diff --git a/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/BUILD.bazel
index 522ae93..367ec8a 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/BUILD.bazel
@@ -58,8 +58,6 @@
],
deps = [
":LLVMCPUExtensionsOpGen",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:TransformDialect",
],
diff --git a/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/CMakeLists.txt
index fa06b14..10f5eae 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/LLVMCPU/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"LLVMCPUExtensionsOps.cpp.inc"
DEPS
::LLVMCPUExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
MLIRIR
MLIRTransformDialect
PUBLIC
diff --git a/compiler/src/iree/compiler/Codegen/LLVMGPU/BUILD.bazel b/compiler/src/iree/compiler/Codegen/LLVMGPU/BUILD.bazel
index e8e27a7..dc6a9d4 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMGPU/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/LLVMGPU/BUILD.bazel
@@ -193,7 +193,6 @@
"//compiler/src/iree/compiler/Dialect/Util/Transforms",
"//compiler/src/iree/compiler/Transforms",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AMDGPUDialect",
"@llvm-project//mlir:AMDGPUToROCDL",
diff --git a/compiler/src/iree/compiler/Codegen/LLVMGPU/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/LLVMGPU/CMakeLists.txt
index 8897d72..a389166 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMGPU/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/LLVMGPU/CMakeLists.txt
@@ -129,7 +129,6 @@
::PassesIncGen
::ROCDLPassHeaders
::ROCDLPassesIncGen
- IREELinalgTransformDialect
LLVMSupport
MLIRAMDGPUDialect
MLIRAMDGPUToROCDL
diff --git a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/BUILD.bazel
index df19585..3ee6e78 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/BUILD.bazel
@@ -66,8 +66,6 @@
"//compiler/src/iree/compiler/Codegen/Dialect/VectorExt/Transforms:VectorExtTransforms",
"//compiler/src/iree/compiler/Codegen/LLVMGPU/Utils",
"//compiler/src/iree/compiler/Codegen/Utils",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AMDGPUDialect",
"@llvm-project//mlir:AffineDialect",
diff --git a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/CMakeLists.txt
index e7ff813..a98db38 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"LLVMGPUExtensionsOps.cpp.inc"
DEPS
::LLVMGPUExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAMDGPUDialect
MLIRAffineDialect
diff --git a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/LLVMGPUExtensions.cpp b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/LLVMGPUExtensions.cpp
index 36a59ec..0438713 100644
--- a/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/LLVMGPUExtensions.cpp
+++ b/compiler/src/iree/compiler/Codegen/LLVMGPU/TransformExtensions/LLVMGPUExtensions.cpp
@@ -6,7 +6,7 @@
#include "LLVMGPUExtensions.h"
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
+#include "iree/compiler/Codegen/Common/ErrorCheckingTrackingListener.h"
#include "iree/compiler/Codegen/Common/GPU/GPUPatterns.h"
#include "iree/compiler/Codegen/Common/GPU/GPUVectorDistribution.h"
#include "iree/compiler/Codegen/Common/GPU/Passes.h"
@@ -29,6 +29,7 @@
#include "mlir/Dialect/NVGPU/IR/NVGPUDialect.h"
#include "mlir/Dialect/NVGPU/Transforms/Transforms.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
+#include "mlir/Dialect/Transform/IR/TransformTypes.h"
#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/BUILD.bazel b/compiler/src/iree/compiler/Codegen/SPIRV/BUILD.bazel
index 3f0cb38..201158f 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/BUILD.bazel
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/BUILD.bazel
@@ -110,7 +110,6 @@
"//compiler/src/iree/compiler/Dialect/Util/Transforms",
"//compiler/src/iree/compiler/Transforms",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineAnalysis",
"@llvm-project//mlir:AffineDialect",
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/CMakeLists.txt b/compiler/src/iree/compiler/Codegen/SPIRV/CMakeLists.txt
index 3a72e99..ec2e172 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/CMakeLists.txt
@@ -79,7 +79,6 @@
DEPS
::PassHeaders
::PassesIncGen
- IREELinalgTransformDialect
LLVMSupport
MLIRAffineAnalysis
MLIRAffineDialect
diff --git a/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/BUILD.bazel
index b528e6b..98eb592 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/BUILD.bazel
@@ -61,8 +61,6 @@
"//compiler/src/iree/compiler/Dialect/Flow/IR",
"//compiler/src/iree/compiler/Dialect/Flow/Transforms",
"//compiler/src/iree/compiler/Dialect/TensorExt/IR",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:Analysis",
"@llvm-project//mlir:ArithDialect",
diff --git a/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/CMakeLists.txt
index e698587..66fe9c2 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Dialect/Flow/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"FlowExtensionsOps.cpp.inc"
DEPS
::FlowExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAnalysis
MLIRArithDialect
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/BUILD.bazel b/compiler/src/iree/compiler/Dialect/Flow/Transforms/BUILD.bazel
index 3b36757..da95c44 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/BUILD.bazel
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/BUILD.bazel
@@ -84,8 +84,6 @@
"//compiler/src/iree/compiler/Dialect/Util/IR",
"//compiler/src/iree/compiler/Dialect/Util/Transforms",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:AffineUtils",
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/CMakeLists.txt b/compiler/src/iree/compiler/Dialect/Flow/Transforms/CMakeLists.txt
index 136de13..69c8b81 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/CMakeLists.txt
@@ -53,8 +53,6 @@
"VerifyInputLegality.cpp"
DEPS
::PassesIncGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAffineDialect
MLIRAffineUtils
diff --git a/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/BUILD.bazel
index 71ccf89..11a03e6 100644
--- a/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/BUILD.bazel
@@ -63,8 +63,6 @@
":LinalgExtExtensionsOpGen",
"//compiler/src/iree/compiler/Dialect/LinalgExt/IR",
"//compiler/src/iree/compiler/Dialect/LinalgExt/Transforms",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:DialectUtils",
"@llvm-project//mlir:IR",
diff --git a/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/CMakeLists.txt
index a634d0e..0e2dd24 100644
--- a/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Dialect/LinalgExt/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"LinalgExtExtensionsOps.cpp.inc"
DEPS
::LinalgExtExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRIR
MLIRLinalgDialect
diff --git a/compiler/src/iree/compiler/GlobalOptimization/BUILD.bazel b/compiler/src/iree/compiler/GlobalOptimization/BUILD.bazel
index 37f58d4..03dd920 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/BUILD.bazel
+++ b/compiler/src/iree/compiler/GlobalOptimization/BUILD.bazel
@@ -103,8 +103,6 @@
"//compiler/src/iree/compiler/Modules/IO/Parameters/Transforms",
"//compiler/src/iree/compiler/Pipelines:Options",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:ArithDialect",
diff --git a/compiler/src/iree/compiler/GlobalOptimization/CMakeLists.txt b/compiler/src/iree/compiler/GlobalOptimization/CMakeLists.txt
index 0b5cfb1..050b3c9 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/CMakeLists.txt
+++ b/compiler/src/iree/compiler/GlobalOptimization/CMakeLists.txt
@@ -67,8 +67,6 @@
DEPS
::PassHeaders
::PassesIncGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRAffineDialect
MLIRArithDialect
diff --git a/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp b/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
index b4e177e..4077d76 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
+++ b/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
@@ -4,7 +4,6 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "iree-dialects/Transforms/TransformMatchers.h"
#include "iree/compiler/Dialect/Flow/Transforms/RegionOpUtils.h"
#include "iree/compiler/Dialect/LinalgExt/IR/LinalgExtDialect.h"
#include "iree/compiler/Dialect/LinalgExt/IR/LinalgExtInterfaces.h"
@@ -19,6 +18,7 @@
#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/Linalg/Utils/Utils.h"
+#include "mlir/Dialect/Math/IR/Math.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/IR/BuiltinAttributes.h"
@@ -28,7 +28,6 @@
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
using namespace mlir;
-using transform_ext::StructuredOpMatcher;
namespace mlir::iree_compiler::GlobalOptimization {
@@ -374,6 +373,293 @@
// Softmax Raising
//===----------------------------------------------------------------------===//
+// Recognizing a numerically-stabilized softmax means walking a small graph of
+// `linalg.generic` ops. The helpers below match the individual nodes of that
+// graph directly, replacing the generic `transform_ext` matcher framework that
+// used to live in iree-dialects. The matched dataflow, working back from the
+// root op, is:
+//
+// max = reduce_max(src) (reduction over the innermost dim)
+// sub = src - broadcast(max)
+// exp = exp(sub)
+// sum = reduce_add(exp) (reduction over the innermost dim)
+// root = exp * reciprocal(sum) OR exp / broadcast(sum)
+//
+// where each broadcast is either implicit (the consumer indexing map drops the
+// innermost dim) or explicit (a pass-through `linalg.generic` that broadcasts
+// along the innermost dim).
+
+// Returns true if every iterator of `op` is parallel.
+static bool isAllParallel(linalg::GenericOp op) {
+ return llvm::all_of(op.getIteratorTypesArray(), [](utils::IteratorType t) {
+ return t == utils::IteratorType::parallel;
+ });
+}
+
+// Returns true if `operand`'s indexing map is the identity.
+static bool isIdentityOperand(linalg::GenericOp op, OpOperand *operand) {
+ return op.getMatchingIndexingMap(operand).isIdentity();
+}
+
+// Returns true if `operand`'s indexing map is the projection that drops the
+// innermost (last) loop dim, e.g. (d0, d1, d2) -> (d0, d1).
+static bool dropsInnermostDim(linalg::GenericOp op, OpOperand *operand) {
+ AffineMap map = op.getMatchingIndexingMap(operand);
+ unsigned numLoops = op.getNumLoops();
+ if (!map.isProjectedPermutation() || map.getNumResults() + 1 != numLoops) {
+ return false;
+ }
+ for (unsigned i = 0, e = map.getNumResults(); i < e; ++i) {
+ if (map.getDimPosition(i) != i) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Returns the single compute op of `op`'s body when the body is exactly that op
+// followed by a `linalg.yield` of its single result; otherwise nullptr.
+static Operation *getSingleComputeOp(linalg::GenericOp op) {
+ Block *body = op.getBlock();
+ if (body->getOperations().size() != 2) {
+ return nullptr;
+ }
+ Operation *computeOp = &body->front();
+ auto yieldOp = cast<linalg::YieldOp>(body->getTerminator());
+ if (computeOp->getNumResults() != 1 || yieldOp.getNumOperands() != 1 ||
+ yieldOp.getOperand(0).getDefiningOp() != computeOp) {
+ return nullptr;
+ }
+ return computeOp;
+}
+
+// Returns true if `v` references block argument number `argNumber` of `block`.
+static bool isBlockArg(Value v, Block *block, unsigned argNumber) {
+ auto arg = dyn_cast<BlockArgument>(v);
+ return arg && arg.getOwner() == block && arg.getArgNumber() == argNumber;
+}
+
+// Returns true if `op`'s body is a single `OpTy` whose operands are the leading
+// block arguments in order. When `commutative`, a two-operand body may also use
+// the arguments in swapped order.
+template <typename OpTy>
+static bool hasSingleOpBody(linalg::GenericOp op, bool commutative = false) {
+ Operation *computeOp = getSingleComputeOp(op);
+ if (!isa_and_nonnull<OpTy>(computeOp)) {
+ return false;
+ }
+ Block *body = op.getBlock();
+ if (commutative && computeOp->getNumOperands() == 2) {
+ return (isBlockArg(computeOp->getOperand(0), body, 0) &&
+ isBlockArg(computeOp->getOperand(1), body, 1)) ||
+ (isBlockArg(computeOp->getOperand(0), body, 1) &&
+ isBlockArg(computeOp->getOperand(1), body, 0));
+ }
+ for (auto [index, operand] : llvm::enumerate(computeOp->getOperands())) {
+ if (!isBlockArg(operand, body, index)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Returns true if `op`'s body just yields its (single) block argument, i.e. it
+// is a pure broadcast/transpose of the input.
+static bool isPassThroughBody(linalg::GenericOp op) {
+ Block *body = op.getBlock();
+ if (body->getOperations().size() != 1) {
+ return false;
+ }
+ auto yieldOp = cast<linalg::YieldOp>(body->getTerminator());
+ for (auto [index, operand] : llvm::enumerate(yieldOp.getOperands())) {
+ if (!isBlockArg(operand, body, index)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Returns true if `v` is a float constant satisfying `pred`.
+static bool isFloatConstant(Value v, llvm::function_ref<bool(APFloat)> pred) {
+ auto cstOp = v.getDefiningOp<arith::ConstantFloatOp>();
+ return cstOp && pred(cstOp.value());
+}
+
+// Returns true if `v` is a `linalg.fill` whose scalar value is a float constant
+// satisfying `pred`.
+static bool isFilledWith(Value v, llvm::function_ref<bool(APFloat)> pred) {
+ auto fillOp = v.getDefiningOp<linalg::FillOp>();
+ return fillOp && isFloatConstant(fillOp.getInputs()[0], pred);
+}
+
+// Matches a single-input `linalg.generic` reduction over the innermost dim with
+// a commutative `OpTy` body and an init produced by a `linalg.fill` of a
+// constant satisfying `fillPred`. Returns the reduced value on success.
+template <typename OpTy>
+static Value
+matchInnermostReduction(Value v, llvm::function_ref<bool(APFloat)> fillPred) {
+ auto op = v.getDefiningOp<linalg::GenericOp>();
+ if (!op || op.getNumDpsInputs() != 1 || op.getNumDpsInits() != 1) {
+ return {};
+ }
+ SmallVector<utils::IteratorType> iterators = op.getIteratorTypesArray();
+ if (iterators.empty() || iterators.back() != utils::IteratorType::reduction) {
+ return {};
+ }
+ for (unsigned i = 0, e = iterators.size() - 1; i < e; ++i) {
+ if (iterators[i] != utils::IteratorType::parallel) {
+ return {};
+ }
+ }
+ OpOperand *input = op.getDpsInputOperand(0);
+ OpOperand *init = op.getDpsInitOperand(0);
+ if (!isIdentityOperand(op, input) || !dropsInnermostDim(op, init) ||
+ !hasSingleOpBody<OpTy>(op, /*commutative=*/true) ||
+ !isFilledWith(init->get(), fillPred)) {
+ return {};
+ }
+ return input->get();
+}
+
+// Matches a single-input all-parallel `linalg.generic` with identity-mapped
+// input and output and an `OpTy` body. Returns the input value on success.
+template <typename OpTy>
+static Value matchUnaryElementwise(Value v) {
+ auto op = v.getDefiningOp<linalg::GenericOp>();
+ if (!op || op.getNumDpsInputs() != 1 || op.getNumDpsInits() != 1 ||
+ !isAllParallel(op)) {
+ return {};
+ }
+ if (!isIdentityOperand(op, op.getDpsInputOperand(0)) ||
+ !isIdentityOperand(op, op.getDpsInitOperand(0)) ||
+ !hasSingleOpBody<OpTy>(op)) {
+ return {};
+ }
+ return op.getDpsInputOperand(0)->get();
+}
+
+// Matches a reciprocal `linalg.generic` (body `divf 1.0, %arg0`) that is
+// single-input, all-parallel and identity-mapped. Returns the input value.
+static Value matchReciprocal(Value v) {
+ auto op = v.getDefiningOp<linalg::GenericOp>();
+ if (!op || op.getNumDpsInputs() != 1 || op.getNumDpsInits() != 1 ||
+ !isAllParallel(op)) {
+ return {};
+ }
+ if (!isIdentityOperand(op, op.getDpsInputOperand(0)) ||
+ !isIdentityOperand(op, op.getDpsInitOperand(0))) {
+ return {};
+ }
+ auto divOp = dyn_cast_or_null<arith::DivFOp>(getSingleComputeOp(op));
+ if (!divOp ||
+ !isFloatConstant(divOp.getOperand(0),
+ [](APFloat f) { return f.convertToDouble() == 1.0; }) ||
+ !isBlockArg(divOp.getOperand(1), op.getBlock(), 0)) {
+ return {};
+ }
+ return op.getDpsInputOperand(0)->get();
+}
+
+// Resolves `operand` of `consumer`, which is expected to carry the broadcast of
+// an innermost-reduced value, to that pre-broadcast value. Handles both the
+// implicit broadcast (the operand's map drops the innermost dim) and the
+// explicit broadcast (the operand is produced by a pass-through generic that
+// broadcasts along the innermost dim).
+static Value resolveBroadcastedReduction(linalg::GenericOp consumer,
+ OpOperand *operand) {
+ if (dropsInnermostDim(consumer, operand)) {
+ return operand->get();
+ }
+ if (!isIdentityOperand(consumer, operand)) {
+ return {};
+ }
+ auto bcast = operand->get().getDefiningOp<linalg::GenericOp>();
+ if (!bcast || bcast.getNumDpsInputs() != 1 || bcast.getNumDpsInits() != 1 ||
+ !isAllParallel(bcast) || !isPassThroughBody(bcast) ||
+ !dropsInnermostDim(bcast, bcast.getDpsInputOperand(0)) ||
+ !isIdentityOperand(bcast, bcast.getDpsInitOperand(0))) {
+ return {};
+ }
+ return bcast.getDpsInputOperand(0)->get();
+}
+
+// Recognizes the softmax graph rooted at `rootOp` and returns the softmax
+// source value on success.
+static FailureOr<Value> matchSoftmax(linalg::LinalgOp rootOp) {
+ auto root = dyn_cast<linalg::GenericOp>(rootOp.getOperation());
+ if (!root || root.getNumDpsInputs() != 2 || root.getNumDpsInits() != 1 ||
+ !isAllParallel(root)) {
+ return failure();
+ }
+ // The numerator (exp(...)) always flows in as input 0 with an identity map.
+ OpOperand *numerator = root.getDpsInputOperand(0);
+ OpOperand *denominator = root.getDpsInputOperand(1);
+ if (!isIdentityOperand(root, numerator)) {
+ return failure();
+ }
+
+ // The root normalizes either as `exp * reciprocal(sum)` or `exp / sum`.
+ Value sumValue;
+ if (hasSingleOpBody<arith::MulFOp>(root, /*commutative=*/true)) {
+ if (!dropsInnermostDim(root, denominator)) {
+ return failure();
+ }
+ sumValue = matchReciprocal(denominator->get());
+ } else if (hasSingleOpBody<arith::DivFOp>(root)) {
+ sumValue = resolveBroadcastedReduction(root, denominator);
+ }
+ if (!sumValue) {
+ return failure();
+ }
+
+ // exp = exp(sub); sum = reduce_add(exp).
+ Value expValue = numerator->get();
+ Value subValue = matchUnaryElementwise<math::ExpOp>(expValue);
+ Value summedValue = matchInnermostReduction<arith::AddFOp>(
+ sumValue, [](APFloat f) { return f.isZero(); });
+ if (!subValue || summedValue != expValue) {
+ return failure();
+ }
+
+ // sub = src - broadcast(max).
+ auto subOp = subValue.getDefiningOp<linalg::GenericOp>();
+ if (!subOp || subOp.getNumDpsInputs() != 2 || subOp.getNumDpsInits() != 1 ||
+ !isAllParallel(subOp) ||
+ !isIdentityOperand(subOp, subOp.getDpsInitOperand(0)) ||
+ !hasSingleOpBody<arith::SubFOp>(subOp)) {
+ return failure();
+ }
+ OpOperand *subSource = subOp.getDpsInputOperand(0);
+ if (!isIdentityOperand(subOp, subSource)) {
+ return failure();
+ }
+ Value maxValue =
+ resolveBroadcastedReduction(subOp, subOp.getDpsInputOperand(1));
+ if (!maxValue) {
+ return failure();
+ }
+
+ // max = reduce_max(src), reducing the same source the subtraction reads. The
+ // init must be -inf or the lowest finite value. Accept both arith.maximumf
+ // (NaN-propagating, as emitted by e.g. StableHLO frontends) and arith.maxnumf
+ // (NaN-ignoring, which is what linalg.softmax itself decomposes to), since
+ // both denote the stabilizing max of a softmax.
+ auto isNegInfOrLowest = [](APFloat f) {
+ return (f.isLargest() || f.isInfinity()) && f.isNegative();
+ };
+ Value source = subSource->get();
+ Value reducedValue =
+ matchInnermostReduction<arith::MaximumFOp>(maxValue, isNegInfOrLowest);
+ if (!reducedValue) {
+ reducedValue =
+ matchInnermostReduction<arith::MaxNumFOp>(maxValue, isNegInfOrLowest);
+ }
+ if (reducedValue != source) {
+ return failure();
+ }
+ return source;
+}
+
class RaiseSoftmax : public OpInterfaceRewritePattern<linalg::LinalgOp> {
public:
using OpInterfaceRewritePattern<linalg::LinalgOp>::OpInterfaceRewritePattern;
@@ -386,19 +672,15 @@
return failure();
}
- transform_ext::MatcherContext matcherContext;
- transform_ext::StructuredOpMatcher *maxReduction;
- transform_ext::StructuredOpMatcher *softmaxroot;
- makeSoftmaxMatcher(matcherContext, maxReduction, softmaxroot);
- if (!matchPattern(linalgOp, *softmaxroot)) {
+ FailureOr<Value> src = matchSoftmax(linalgOp);
+ if (failed(src)) {
return rewriter.notifyMatchFailure(linalgOp,
"failed to match softmax root");
}
- Value src = maxReduction->getCaptured()->getOperand(0);
rewriter.setInsertionPoint(linalgOp);
rewriter.replaceOpWithNewOp<linalg::SoftmaxOp>(
- linalgOp, linalgOp->getResultTypes(), src,
+ linalgOp, linalgOp->getResultTypes(), *src,
linalgOp.getDpsInitOperand(0)->get(), linalgOp.getNumLoops() - 1);
return success();
}
diff --git a/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir b/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
index fc1b4e2..877b169 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
+++ b/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
@@ -168,6 +168,154 @@
// -----
+// The stabilizing max may use arith.maxnumf (NaN-ignoring).
+// CHECK-LABEL: @softmax_maxnumf
+// CHECK-SAME: %[[ARG:.+]]: tensor<2x4xf32>
+// CHECK: %[[S:.+]] = linalg.softmax dimension(1) ins(%[[ARG]] : tensor<2x4xf32>)
+// CHECK: util.return %[[S]]
+util.func public @softmax_maxnumf(%src : tensor<2x4xf32>) -> (tensor<2x4xf32>) {
+ %cst0 = arith.constant 0.000000e+00 : f32
+ %cstlow = arith.constant -3.40282347E+38 : f32
+ %e1 = tensor.empty() : tensor<2xf32>
+ %e2 = tensor.empty() : tensor<2x4xf32>
+ %fillmax = linalg.fill ins(%cstlow : f32) outs(%e1 : tensor<2xf32>) -> tensor<2xf32>
+ %max = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0)>], iterator_types = ["parallel", "reduction"]} ins(%src : tensor<2x4xf32>) outs(%fillmax : tensor<2xf32>) {
+ ^bb0(%a: f32, %b: f32):
+ %m = arith.maxnumf %a, %b : f32
+ linalg.yield %m : f32
+ } -> tensor<2xf32>
+ %sub = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0)>, affine_map<(d0, d1) -> (d0, d1)>], iterator_types = ["parallel", "parallel"]} ins(%src, %max : tensor<2x4xf32>, tensor<2xf32>) outs(%e2 : tensor<2x4xf32>) {
+ ^bb0(%a: f32, %b: f32, %c: f32):
+ %s = arith.subf %a, %b : f32
+ linalg.yield %s : f32
+ } -> tensor<2x4xf32>
+ %exp = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>], iterator_types = ["parallel", "parallel"]} ins(%sub : tensor<2x4xf32>) outs(%e2 : tensor<2x4xf32>) {
+ ^bb0(%a: f32, %b: f32):
+ %e = math.exp %a : f32
+ linalg.yield %e : f32
+ } -> tensor<2x4xf32>
+ %fillsum = linalg.fill ins(%cst0 : f32) outs(%e1 : tensor<2xf32>) -> tensor<2xf32>
+ %sum = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0)>], iterator_types = ["parallel", "reduction"]} ins(%exp : tensor<2x4xf32>) outs(%fillsum : tensor<2xf32>) {
+ ^bb0(%a: f32, %b: f32):
+ %s = arith.addf %a, %b : f32
+ linalg.yield %s : f32
+ } -> tensor<2xf32>
+ %div = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0)>, affine_map<(d0, d1) -> (d0, d1)>], iterator_types = ["parallel", "parallel"]} ins(%exp, %sum : tensor<2x4xf32>, tensor<2xf32>) outs(%e2 : tensor<2x4xf32>) {
+ ^bb0(%a: f32, %b: f32, %c: f32):
+ %d = arith.divf %a, %b : f32
+ linalg.yield %d : f32
+ } -> tensor<2x4xf32>
+ util.return %div : tensor<2x4xf32>
+}
+
+// -----
+
+// Negative test: max init is 0.0, not -inf/lowest.
+// CHECK-LABEL: @not_softmax_wrong_max_init
+// CHECK-NOT: linalg.softmax
+util.func public @not_softmax_wrong_max_init(%src : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>) {
+ %cst = arith.constant 1.000000e+00 : f32
+ %cst_0 = arith.constant 0.000000e+00 : f32
+ %c_0_index = arith.constant 0 : index
+ %c_1_index = arith.constant 1 : index
+ %c_2_index = arith.constant 2 : index
+ %dim_0 = tensor.dim %src, %c_0_index : tensor<?x?x?xf32>
+ %dim_1 = tensor.dim %src, %c_1_index : tensor<?x?x?xf32>
+ %dim_2 = tensor.dim %src, %c_2_index : tensor<?x?x?xf32>
+ %1 = tensor.empty(%dim_0, %dim_1) : tensor<?x?xf32>
+ // Wrong init: 0.0 rather than -inf / lowest.
+ %2 = linalg.fill ins(%cst_0 : f32) outs(%1 : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %3 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} ins(%src : tensor<?x?x?xf32>) outs(%2 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.maximumf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %4 = tensor.empty(%dim_0, %dim_1, %dim_2) : tensor<?x?x?xf32>
+ %5 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%src, %3 : tensor<?x?x?xf32>, tensor<?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32, %arg2: f32):
+ %11 = arith.subf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ %6 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%5 : tensor<?x?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = math.exp %arg0 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ %7 = linalg.fill ins(%cst_0 : f32) outs(%1 : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %8 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} ins(%6 : tensor<?x?x?xf32>) outs(%7 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.addf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %9 = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>], iterator_types = ["parallel", "parallel"]} ins(%8 : tensor<?x?xf32>) outs(%1 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.divf %cst, %arg0 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %10 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%6, %9 : tensor<?x?x?xf32>, tensor<?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32, %arg2: f32):
+ %11 = arith.mulf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ util.return %10 : tensor<?x?x?xf32>
+}
+
+// -----
+
+// Negative test: max and subtraction read different sources.
+// CHECK-LABEL: @not_softmax_mismatched_source
+// CHECK-NOT: linalg.softmax
+util.func public @not_softmax_mismatched_source(%src : tensor<?x?x?xf32>, %other : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>) {
+ %cst = arith.constant 1.000000e+00 : f32
+ %cst_0 = arith.constant 0.000000e+00 : f32
+ %cst_1 = arith.constant -3.40282347E+38 : f32
+ %c_0_index = arith.constant 0 : index
+ %c_1_index = arith.constant 1 : index
+ %c_2_index = arith.constant 2 : index
+ %dim_0 = tensor.dim %src, %c_0_index : tensor<?x?x?xf32>
+ %dim_1 = tensor.dim %src, %c_1_index : tensor<?x?x?xf32>
+ %dim_2 = tensor.dim %src, %c_2_index : tensor<?x?x?xf32>
+ %1 = tensor.empty(%dim_0, %dim_1) : tensor<?x?xf32>
+ %2 = linalg.fill ins(%cst_1 : f32) outs(%1 : tensor<?x?xf32>) -> tensor<?x?xf32>
+ // Reduces %src ...
+ %3 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} ins(%src : tensor<?x?x?xf32>) outs(%2 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.maximumf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %4 = tensor.empty(%dim_0, %dim_1, %dim_2) : tensor<?x?x?xf32>
+ // ... but subtracts from %other.
+ %5 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%other, %3 : tensor<?x?x?xf32>, tensor<?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32, %arg2: f32):
+ %11 = arith.subf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ %6 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%5 : tensor<?x?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = math.exp %arg0 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ %7 = linalg.fill ins(%cst_0 : f32) outs(%1 : tensor<?x?xf32>) -> tensor<?x?xf32>
+ %8 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"]} ins(%6 : tensor<?x?x?xf32>) outs(%7 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.addf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %9 = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>], iterator_types = ["parallel", "parallel"]} ins(%8 : tensor<?x?xf32>) outs(%1 : tensor<?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32):
+ %11 = arith.divf %cst, %arg0 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?xf32>
+ %10 = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} ins(%6, %9 : tensor<?x?x?xf32>, tensor<?x?xf32>) outs(%4 : tensor<?x?x?xf32>) {
+ ^bb0(%arg0: f32, %arg1: f32, %arg2: f32):
+ %11 = arith.mulf %arg0, %arg1 : f32
+ linalg.yield %11 : f32
+ } -> tensor<?x?x?xf32>
+ util.return %10 : tensor<?x?x?xf32>
+}
+
+// -----
+
util.func public @aTransposeBMatmul(%arg0 : tensor<10x20xf32>,
%arg1 : tensor<40x20xf32>) -> tensor<10x40xf32> {
%0 = tensor.empty() : tensor<20x40xf32>
diff --git a/compiler/src/iree/compiler/Preprocessing/TransformExtensions/BUILD.bazel b/compiler/src/iree/compiler/Preprocessing/TransformExtensions/BUILD.bazel
index 5ddf952..7982c8f 100644
--- a/compiler/src/iree/compiler/Preprocessing/TransformExtensions/BUILD.bazel
+++ b/compiler/src/iree/compiler/Preprocessing/TransformExtensions/BUILD.bazel
@@ -60,8 +60,6 @@
"//compiler/src/iree/compiler/Dialect/LinalgExt/IR",
"//compiler/src/iree/compiler/Dialect/LinalgExt/Utils",
"//compiler/src/iree/compiler/Utils",
- "//llvm-external-projects/iree-dialects:IREEDialectsTransforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:LinalgInterfaces",
diff --git a/compiler/src/iree/compiler/Preprocessing/TransformExtensions/CMakeLists.txt b/compiler/src/iree/compiler/Preprocessing/TransformExtensions/CMakeLists.txt
index 21977dd..633f4e8 100644
--- a/compiler/src/iree/compiler/Preprocessing/TransformExtensions/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Preprocessing/TransformExtensions/CMakeLists.txt
@@ -31,8 +31,6 @@
"PreprocessingExtensionsOps.cpp.inc"
DEPS
::PreprocessingExtensionsOpGen
- IREEDialectsTransforms
- IREELinalgTransformDialect
LLVMSupport
MLIRIR
MLIRLinalgInterfacesIncGenLib
diff --git a/compiler/src/iree/compiler/Tools/BUILD.bazel b/compiler/src/iree/compiler/Tools/BUILD.bazel
index 3ddd96e..5a8acd2 100644
--- a/compiler/src/iree/compiler/Tools/BUILD.bazel
+++ b/compiler/src/iree/compiler/Tools/BUILD.bazel
@@ -76,7 +76,6 @@
"//compiler/src/iree/compiler/Preprocessing:Passes",
"//compiler/src/iree/compiler/Preprocessing/TransformExtensions:PreprocessingExtensions",
"//compiler/src/iree/compiler/Transforms",
- "//llvm-external-projects/iree-dialects:IREELinalgTransformDialect",
"@llvm-project//mlir:IR",
],
)
diff --git a/compiler/src/iree/compiler/Tools/CMakeLists.txt b/compiler/src/iree/compiler/Tools/CMakeLists.txt
index b8be6ff..de2f684 100644
--- a/compiler/src/iree/compiler/Tools/CMakeLists.txt
+++ b/compiler/src/iree/compiler/Tools/CMakeLists.txt
@@ -24,7 +24,6 @@
"init_iree_dialects.h"
"init_iree_passes.h"
DEPS
- IREELinalgTransformDialect
MLIRIR
iree::compiler::Bindings::Native::Transforms
iree::compiler::Bindings::TFLite::Transforms
diff --git a/docs/website/generate_extra_files.sh b/docs/website/generate_extra_files.sh
index 25be565..c1014c6 100755
--- a/docs/website/generate_extra_files.sh
+++ b/docs/website/generate_extra_files.sh
@@ -52,7 +52,6 @@
# Delete any dialect docs we don't want to publish (yet?).
rm "${BUILD_DIALECTS_PROCESSED_DIR}/SimpleIODialect.md" # Sample dialect, just ignore
-rm "${BUILD_DIALECTS_PROCESSED_DIR}/StructuredTransformOpsExt.md" # Dialect extensions
# Trim "Dialect"/"Passes" suffix from file names e.g. FlowDialect.md -> Flow.md.
for f in ${BUILD_DIALECTS_PROCESSED_DIR}/*Dialect.md; do
diff --git a/llvm-external-projects/iree-dialects/BUILD.bazel b/llvm-external-projects/iree-dialects/BUILD.bazel
index c2dce58..811772b 100644
--- a/llvm-external-projects/iree-dialects/BUILD.bazel
+++ b/llvm-external-projects/iree-dialects/BUILD.bazel
@@ -1,5 +1,4 @@
-load("@llvm-project//mlir:tblgen.bzl", "gentbl_cc_library", "td_library")
-load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+load("@rules_cc//cc:defs.bzl", "cc_binary")
package(
default_visibility = ["//visibility:public"],
@@ -26,212 +25,6 @@
)
################################################################################
-# Tablegen exports
-################################################################################
-
-td_library(
- name = "TdFiles",
- srcs = glob(
- [
- "include/iree-dialects/Dialect/Input/*.td",
- "include/iree-dialects/Dialect/LinalgTransform/*.td",
- "python/iree/compiler/dialects/*.td",
- ],
- allow_empty = True,
- ),
- includes = ["include"],
- deps = [
- "@llvm-project//mlir:BuiltinDialectTdFiles",
- "@llvm-project//mlir:InferTypeOpInterfaceTdFiles",
- "@llvm-project//mlir:OpBaseTdFiles",
- "@llvm-project//mlir:PDLDialectTdFiles",
- "@llvm-project//mlir:SideEffectInterfacesTdFiles",
- "@llvm-project//mlir:TransformDialectTdFiles",
- ],
-)
-
-################################################################################
-# IREELinalgTransform Dialect
-################################################################################
-
-cc_library(
- name = "IREEDialectsTransforms",
- srcs = glob(
- [
- "lib/Transforms/*.cpp",
- ],
- allow_empty = True,
- ),
- hdrs = glob(
- [
- "include/iree-dialects/Transforms/*.h",
- ],
- allow_empty = True,
- ),
- includes = ["include"],
- deps = [
- "@llvm-project//llvm:Support",
- "@llvm-project//mlir:Analysis",
- "@llvm-project//mlir:ArithDialect",
- "@llvm-project//mlir:DialectUtils",
- "@llvm-project//mlir:FuncDialect",
- "@llvm-project//mlir:FunctionInterfaces",
- "@llvm-project//mlir:IR",
- "@llvm-project//mlir:LinalgDialect",
- "@llvm-project//mlir:LinalgInterfaces",
- "@llvm-project//mlir:MathDialect",
- "@llvm-project//mlir:Rewrite",
- "@llvm-project//mlir:SCFDialect",
- "@llvm-project//mlir:TensorDialect",
- "@llvm-project//mlir:TransformDialect",
- "@llvm-project//mlir:TransformDialectInterfaces",
- "@llvm-project//mlir:TransformUtils",
- "@llvm-project//mlir:Transforms",
- ],
-)
-
-gentbl_cc_library(
- name = "IREELinalgTransformStructuredIncGen",
- strip_include_prefix = "include",
- tbl_outs = [
- (
- ["--gen-op-decls"],
- "include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h.inc",
- ),
- (
- ["--gen-op-defs"],
- "include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.cpp.inc",
- ),
- ],
- tblgen = "@llvm-project//mlir:mlir-tblgen",
- td_file = "include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.td",
- deps = [
- ":TdFiles",
- ],
-)
-
-cc_library(
- name = "IREELinalgTransformDialect",
- srcs = glob(
- [
- "lib/Dialect/LinalgTransform/IR/*.cpp",
- "lib/Dialect/LinalgTransform/IR/*.h",
- ],
- allow_empty = True,
- ),
- hdrs = glob(
- [
- "include/iree-dialects/Dialect/LinalgTransform/*.h",
- ],
- allow_empty = True,
- ),
- includes = ["include"],
- deps = [
- ":IREEDialectsTransforms",
- ":IREELinalgTransformStructuredIncGen",
- "@llvm-project//llvm:Support",
-
- # Dialects
- "@llvm-project//mlir:AffineDialect",
- "@llvm-project//mlir:AffineUtils",
- "@llvm-project//mlir:AsyncDialect",
- "@llvm-project//mlir:ArithDialect",
- "@llvm-project//mlir:BufferizationDialect",
- "@llvm-project//mlir:BufferizationTransforms",
- "@llvm-project//mlir:FuncDialect",
- "@llvm-project//mlir:FunctionInterfaces",
- "@llvm-project//mlir:LinalgDialect",
- "@llvm-project//mlir:LLVMDialect",
- "@llvm-project//mlir:PDLDialect",
- "@llvm-project//mlir:SCFDialect",
- "@llvm-project//mlir:SCFUtils",
- "@llvm-project//mlir:Support",
- "@llvm-project//mlir:TensorDialect",
- "@llvm-project//mlir:TilingInterface",
- "@llvm-project//mlir:TransformDialect",
- "@llvm-project//mlir:TransformDialectInterfaces",
- "@llvm-project//mlir:TransformPDLExtension",
-
- # IR
- "@llvm-project//mlir:IR",
- "@llvm-project//mlir:Parser",
- "@llvm-project//mlir:Pass",
- "@llvm-project//mlir:Rewrite",
-
- # Interfaces
- "@llvm-project//mlir:ControlFlowInterfaces",
-
- # Transforms
- "@llvm-project//mlir:AffineToStandard",
- "@llvm-project//mlir:AsyncTransforms",
- "@llvm-project//mlir:LinalgTransforms",
- "@llvm-project//mlir:MemRefTransforms",
- "@llvm-project//mlir:ReconcileUnrealizedCasts",
- "@llvm-project//mlir:SCFTransforms",
- "@llvm-project//mlir:TensorTransformOps",
- "@llvm-project//mlir:Transforms",
- "@llvm-project//mlir:TransformUtils",
- "@llvm-project//mlir:VectorToSCF",
-
- # Utils
- "@llvm-project//mlir:ArithUtils",
- "@llvm-project//mlir:DialectUtils",
-
- # Conversions
- "@llvm-project//mlir:AsyncToLLVM",
- "@llvm-project//mlir:FuncToLLVM",
- "@llvm-project//mlir:IndexToLLVM",
- "@llvm-project//mlir:LinalgToStandard",
- "@llvm-project//mlir:MathToLLVM",
- "@llvm-project//mlir:MemRefToLLVM",
- "@llvm-project//mlir:SCFToControlFlow",
- "@llvm-project//mlir:VectorToLLVM",
- ],
-)
-
-################################################################################
-# CAPI
-################################################################################
-
-cc_library(
- name = "CAPI",
- srcs = glob(
- ["lib/CAPI/*.cpp"],
- allow_empty = True,
- ),
- hdrs = glob(
- ["include/iree-dialects-c/*.h"],
- allow_empty = True,
- ),
- includes = ["include"],
- deps = [
- ":IREELinalgTransformDialect",
- "@llvm-project//mlir:CAPIIR",
- "@llvm-project//mlir:IR",
- "@llvm-project//mlir:LinalgTransformOps",
- "@llvm-project//mlir:Support",
- "@llvm-project//mlir:TransformDialect",
- ],
-)
-
-################################################################################
-# Test lib
-################################################################################
-
-cc_library(
- name = "IREEDialectsTest",
- deps = [
- ":IREEDialectsTransforms",
- ":IREELinalgTransformDialect",
- "@llvm-project//mlir:IR",
- "@llvm-project//mlir:Pass",
- "@llvm-project//mlir:Rewrite",
- "@llvm-project//mlir:TransformUtils",
- "@llvm-project//mlir:Transforms",
- ],
-)
-
-################################################################################
# Tools
################################################################################
@@ -242,8 +35,6 @@
],
tags = ["hostonly"],
deps = [
- ":IREEDialectsTest",
- ":IREELinalgTransformDialect",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:ArithDialect",
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects-c/Dialects.h b/llvm-external-projects/iree-dialects/include/iree-dialects-c/Dialects.h
deleted file mode 100644
index c729238..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects-c/Dialects.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The IREE Authors
-//
-// Licensed 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 IREE_DIALECTS_C_DIALECTS_H
-#define IREE_DIALECTS_C_DIALECTS_H
-
-#include "mlir-c/IR.h"
-#include "mlir-c/Pass.h"
-#include "mlir-c/RegisterEverything.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//===--------------------------------------------------------------------===//
-// TransformDialect
-//===--------------------------------------------------------------------===//
-
-MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Transform, transform);
-
-MLIR_CAPI_EXPORTED void ireeRegisterTransformExtensions(MlirContext context);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // IREE_DIALECTS_C_DIALECTS_H
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/CMakeLists.txt b/llvm-external-projects/iree-dialects/include/iree-dialects/CMakeLists.txt
index 0ca0f41..e69de29 100644
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/CMakeLists.txt
+++ b/llvm-external-projects/iree-dialects/include/iree-dialects/CMakeLists.txt
@@ -1 +0,0 @@
-add_subdirectory(Dialect)
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/CMakeLists.txt b/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/CMakeLists.txt
deleted file mode 100644
index 1da2860..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(LinalgTransform)
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/CMakeLists.txt b/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/CMakeLists.txt
deleted file mode 100644
index c0ebeb4..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-function(_add_transform_dialect_extension)
- set(LLVM_TARGET_DEFINITIONS StructuredTransformOpsExt.td)
- mlir_tablegen(StructuredTransformOpsExt.h.inc -gen-op-decls)
- mlir_tablegen(StructuredTransformOpsExt.cpp.inc -gen-op-defs)
- add_public_tablegen_target(IREELinalgTransformExtIncGen)
- add_dependencies(mlir-headers IREELinalgTransformExtIncGen)
-endfunction()
-
-function(_add_structured_transform_doc)
- set(LLVM_TARGET_DEFINITIONS StructuredTransformOpsExt.td)
- mlir_tablegen(StructuredTransformOpsExt.md -gen-dialect-doc)
- set(GEN_DOC_FILE ${IREE_DIALECTS_BINARY_DIR}/docs/Dialects/StructuredTransformOpsExt.md)
- add_custom_command(
- OUTPUT ${GEN_DOC_FILE}
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_BINARY_DIR}/StructuredTransformOpsExt.md
- ${GEN_DOC_FILE}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/StructuredTransformOpsExt.md)
- add_custom_target(StructuredTransformOpsExtDocGen DEPENDS ${GEN_DOC_FILE})
- add_dependencies(iree-dialects-doc StructuredTransformOpsExtDocGen)
-endfunction()
-
-_add_transform_dialect_extension()
-_add_structured_transform_doc()
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h b/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h
deleted file mode 100644
index c7b6d0d..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2022 The IREE Authors
-//
-// Licensed 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 IREE_DIALECTS_DIALECT_LINALG_TRANSFORM_STRUCTUREDTRANSFORMOPSEXT_H
-#define IREE_DIALECTS_DIALECT_LINALG_TRANSFORM_STRUCTUREDTRANSFORMOPSEXT_H
-
-#include "mlir/Dialect/Tensor/TransformOps/TensorTransformOps.h"
-#include "mlir/Dialect/Transform/IR/TransformDialect.h"
-#include "mlir/Dialect/Transform/IR/TransformOps.h"
-#include "mlir/Dialect/Transform/IR/TransformTypes.h"
-#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
-#include "mlir/IR/ImplicitLocOpBuilder.h"
-#include "mlir/IR/OpDefinition.h"
-
-namespace mlir {
-namespace linalg {
-class LinalgOp;
-} // namespace linalg
-namespace scf {
-class ForOp;
-} // namespace scf
-namespace transform_ext {
-class MatchCallbackOp;
-} // namespace transform_ext
-
-/// Matches a C++ callback previously registered under `callbackName` and
-/// taking arguments `args`.
-/// Unpacks a number of handles `N` (asserts there are exactly `N` matched
-/// ops but this could be relaxed if needed). Returns the tuple of handles.
-template <int N, typename... MatchingArgs>
-auto unpackRegisteredMatchCallback(ImplicitLocOpBuilder &b,
- StringRef callbackName,
- MatchingArgs... args) {
- SmallVector<Type> matchedTypes(N, transform::AnyOpType::get(b.getContext()));
- auto matchOp = b.create<transform_ext::MatchCallbackOp>(
- matchedTypes, callbackName, std::forward<decltype(args)>(args)...);
- assert(matchOp->getNumResults() == N && "Unexpected number of results");
- std::array<Value, N> a;
- for (int64_t i = 0; i < N; ++i) {
- a[i] = matchOp->getResult(i);
- }
- return std::tuple_cat(a);
-}
-
-/// A tracking listener for tensor IR that checks for payload replacement
-/// errors.
-class ErrorCheckingTrackingListener : public transform::TrackingListener {
-public:
- using transform::TrackingListener::TrackingListener;
-
- ~ErrorCheckingTrackingListener() override {
- assert(status.succeeded() && "must check listener error state");
- }
-
- /// Return "true" if this tracking listener had a failure.
- bool failed() const { return !status.succeeded(); }
-
- /// Check and return the current error state of this listener. In case of a
- /// failure state, only the most recent error is returned. Afterwards, resets
- /// the error state.
- DiagnosedSilenceableFailure checkAndResetError() {
- DiagnosedSilenceableFailure result(std::move(status));
- status = DiagnosedSilenceableFailure::success();
- return result;
- }
-
-private:
- void
- notifyPayloadReplacementNotFound(Operation *op, ValueRange values,
- DiagnosedSilenceableFailure &&diag) override;
-
- /// The error state of this listener. "Success" indicates that no error
- /// happened so far. Otherwise, the status contains the most recent error.
- DiagnosedSilenceableFailure status = DiagnosedSilenceableFailure::success();
-};
-
-} // namespace mlir
-
-#define GET_OP_CLASSES
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h.inc"
-
-namespace mlir {
-namespace transform_ext {
-class StructuredTransformOpsExtension
- : public mlir::transform::TransformDialectExtension<
- StructuredTransformOpsExtension> {
-public:
- StructuredTransformOpsExtension();
-};
-
-} // namespace transform_ext
-} // namespace mlir
-
-#endif // IREE_DIALECTS_DIALECT_LINALG_TRANSFORM_STRUCTUREDTRANSFORMOPSEXT_H
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.td b/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.td
deleted file mode 100644
index 81beb06..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.td
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2022 The IREE Authors
-//
-// Licensed 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 STRUCTURED_TRANSFORM_OPS_EXT
-#define STRUCTURED_TRANSFORM_OPS_EXT
-
-include "mlir/Dialect/Transform/IR/TransformAttrs.td"
-include "mlir/Dialect/Transform/IR/TransformDialect.td"
-include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.td"
-include "mlir/Interfaces/ControlFlowInterfaces.td"
-include "mlir/Interfaces/SideEffectInterfaces.td"
-include "mlir/IR/OpAsmInterface.td"
-include "mlir/IR/OpBase.td"
-
-def RegisterMatchCallbacksOp :
- Op<Transform_Dialect, "iree.register_match_callbacks",
- [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
- DeclareOpInterfaceMethods<TransformOpInterface>,
- ReportTrackingListenerFailuresOpTrait]> {
- let description = [{
- Registers named structured op matcher callbacks specific for IREE to use
- with `transform.iree.match_callback`. This should be called before first
- `match_callback` may be executed following the transform dialect control
- flow.
-
- The callbacks must have a unique name and a signature compatible with
- `MatchCallbacksRegistry::MatchCallbackFn`, which currently means
- `DiagnosedSilenceableFailure(MatchCallbackResult &, Location,
- const TransformState &, ValueRange)`. The callback receives a "result",
- followed by a location at which errors should be reported, a transform
- state at the moment of the _match_ (not registration) and a list of
- handle values passed as operands to the `match_callback` operation.
- It is expected to populate the "result" object with lists of payload
- operations that will be bound to the handles produced by the
- `match_callback` operation. The callback may fail, at which point
- it should produce a silenceable error. The callback currently is not
- allowed to modify the payload IR (though this may be revised in the
- future for the purpose of communicating the properties of the IR
- captured by the match). Therefore, it should not have a reason to
- produce a definite error.
- }];
-
- let arguments = (ins);
- let results = (outs);
- let assemblyFormat = "attr-dict";
- let cppNamespace = "mlir::transform_ext";
-}
-
-def MatchCallbackOp :
- Op<Transform_Dialect, "iree.match_callback",
- [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
- DeclareOpInterfaceMethods<TransformOpInterface>,
- ReportTrackingListenerFailuresOpTrait]> {
- let description = [{
- Performs payload IR matching using a C++ callback registered beforehand.
- The callback is identified by name and is passed the current transform
- state and the list of handle operands, along with information necessary
- for error propagation. See `register_match_callbacks` for the description
- of the callback contract.
-
- If `failure_propagation_mode` is set to `suppress`, any silenceable errors
- in the callback (typically, "failure to match") will be ignored and the
- resulting handles will be associated with empty lists of payload
- operations. Otherwise, silenceable failures are propagated.
- }];
-
- let arguments = (ins StrAttr:$callback_name,
- FailurePropagationMode:$failure_propagation_mode,
- Variadic<TransformHandleTypeInterface>:$inputs);
- let results = (outs Variadic<TransformHandleTypeInterface>:$outputs);
- let assemblyFormat = "`failures` `(` $failure_propagation_mode `)` "
- "$callback_name `(` $inputs `)` attr-dict "
- "`:` functional-type($inputs, $outputs)";
- let cppNamespace = "mlir::transform_ext";
-}
-
-def TakeFirstOp :
- Op<Transform_Dialect, "iree.take_first",
- [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
- DeclareOpInterfaceMethods<TransformOpInterface>,
- ReportTrackingListenerFailuresOpTrait]> {
- let description = [{
- Given an arbitrary list of handles associated with potentially empty lists
- of payload operations, produces two new handles:
-
- - a handle pointing to the same payload operations as the first operand
- handle with a non-empty list of payload operations;
- - a handle pointing to the concatenated list of payload operations
- associated with any other handle.
-
- Note that this does not perform any deduplication.
-
- This operation is useful to select a single target after some potentially
- unsuccessful matches.
- }];
-
- let arguments = (ins Variadic<TransformHandleTypeInterface>:$inputs);
- let results = (outs TransformHandleTypeInterface:$first,
- TransformHandleTypeInterface:$rest);
- let assemblyFormat =
- "$inputs attr-dict `:` functional-type($inputs, results)";
- let cppNamespace = "mlir::transform_ext";
-}
-
-def EmitRemarkOp :
- Op<Transform_Dialect, "iree.emit_remark",
- [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
- TransformOpInterface, TransformEachOpTrait,
- ReportTrackingListenerFailuresOpTrait]> {
- let description = [{
- Emits a diagnostic remark with the given message located at payload ops
- associated with the given handle. This can be used, e.g., for debugging.
- }];
-
- let arguments = (ins TransformHandleTypeInterface:$handle,
- StrAttr:$message);
- let assemblyFormat = "$message `at` $handle attr-dict `:` type($handle)";
- let cppNamespace = "mlir::transform_ext";
-
- let extraClassDeclaration = [{
- ::mlir::DiagnosedSilenceableFailure applyToOne(
- ::mlir::transform::TransformRewriter &rewriter,
- ::mlir::Operation *target,
- ::mlir::transform::ApplyToEachResultList &results,
- ::mlir::transform::TransformState &state);
- }];
-}
-
-#endif // STRUCTURED_TRANSFORM_OPS_EXT
diff --git a/llvm-external-projects/iree-dialects/include/iree-dialects/Transforms/TransformMatchers.h b/llvm-external-projects/iree-dialects/include/iree-dialects/Transforms/TransformMatchers.h
deleted file mode 100644
index 4b7d716..0000000
--- a/llvm-external-projects/iree-dialects/include/iree-dialects/Transforms/TransformMatchers.h
+++ /dev/null
@@ -1,1201 +0,0 @@
-// Copyright 2022 The IREE Authors
-//
-// Licensed 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 IREE_COMPILER_CODEGEN_COMMON_TRANSFORMEXTENSIONS_TRANSFORMMATCHERS_H_
-#define IREE_COMPILER_CODEGEN_COMMON_TRANSFORMEXTENSIONS_TRANSFORMMATCHERS_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-
-#include "mlir/Dialect/Linalg/IR/LinalgInterfaces.h"
-#include "mlir/Dialect/Tensor/IR/Tensor.h"
-#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
-#include "mlir/IR/Matchers.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/StringMap.h"
-
-namespace mlir {
-namespace transform_ext {
-
-//===---------------------------------------------------------------------===//
-// StructuredOpMatcher and predicates.
-//===---------------------------------------------------------------------===//
-
-class StructuredOpMatcher;
-class MatcherContext;
-StructuredOpMatcher &m_StructuredOp(MatcherContext &);
-
-/// A tag indicating the shape being static or dynamic, for use with the
-/// structured op matcher.
-enum class ShapeKind { Static, Dynamic };
-
-/// A placeholder indicating the structured op matcher to check the predicate
-/// for all dimensions.
-struct AllDims {};
-
-/// A predicate indicating the structured op matcher to check the predicate for
-/// all dimensions except the specified ones.
-struct AllDimsExcept {
- explicit AllDimsExcept(std::initializer_list<int64_t> range) {
- llvm::append_range(exceptions, range);
- }
- ArrayRef<int64_t> getExcluded() const { return llvm::ArrayRef(exceptions); }
-
-private:
- SmallVector<int64_t> exceptions;
-};
-
-/// A placeholder indicating the structured op matcher to check the predicate
-/// for all operands of the relevant kind.
-struct AllOperands {};
-
-/// Base class for single-value captures. Concrete captures should inherit this
-/// and forward the constructor via `using Base::Base`.
-template <typename T>
-struct CaptureStaticValue {
- using Base = CaptureStaticValue<T>;
- explicit CaptureStaticValue(T &value) : value(value) {}
- T &value;
-};
-
-/// Captures the (static) size of the dimension.
-struct CaptureDim : public CaptureStaticValue<int64_t> {
- using Base::Base;
-};
-
-/// Captures the (static) sizes of multiple dimensions.
-struct CaptureDims : public CaptureStaticValue<SmallVector<int64_t>> {
- using Base::Base;
-};
-
-/// Captures the contraction dimensions of the target operation.
-struct CaptureIndexingMaps : public CaptureStaticValue<SmallVector<AffineMap>> {
- using Base::Base;
-};
-
-/// Captures the contraction dimensions of the target operation.
-struct CaptureContractionDims
- : public CaptureStaticValue<mlir::linalg::ContractionDimensions> {
- using Base::Base;
-};
-
-/// Captures the convolution dimensions of the target operation.
-struct CaptureConvDims
- : public CaptureStaticValue<mlir::linalg::ConvolutionDimensions> {
- using Base::Base;
-};
-
-/// Captures the rank of the operation.
-struct CaptureRank : public CaptureStaticValue<int64_t> {
- using Base::Base;
-};
-
-/// Captures the bitwidth of an element type.
-struct CaptureElementTypeBitWidth : public CaptureStaticValue<int64_t> {
- using Base::Base;
-};
-
-/// Captures element element type.
-struct CaptureElementType : public CaptureStaticValue<Type> {
- using Base::Base;
-};
-
-template <typename T = Attribute>
-struct CaptureAttribute : public CaptureStaticValue<T> {
- static_assert(std::is_base_of_v<Attribute, T>,
- "can only capture a subclass of Attribute");
- using CaptureStaticValue<T>::CaptureStaticValue;
-};
-
-/// A tag indicating to look for any user of the operation's result that would
-/// satisfy the predicate.
-struct HasAnyUse {};
-
-/// Base class for predicate parameters that can be described with the single
-/// value. Concrete predicate parameters should inherit this and forward the
-/// constructor via `using Base::Base`.
-template <typename T>
-struct SingleValuePredicateParam {
- using Base = SingleValuePredicateParam<T>;
- explicit SingleValuePredicateParam(T value) : value(value) {}
- const T value;
-};
-
-/// Indicates that the dimension must be divisible by the given value.
-struct DivisibleBy : public SingleValuePredicateParam<int64_t> {
- using Base::Base;
-};
-
-/// Indicates that the number of entities must be equal to the given value.
-struct NumEqualsTo : public SingleValuePredicateParam<size_t> {
- using Base::Base;
-};
-
-/// Indicates that the number of entities must be greater than the given value.
-struct NumGreaterEqualTo : public SingleValuePredicateParam<size_t> {
- using Base::Base;
-};
-
-/// Indicates that the number of entities must be greater than the given value.
-struct NumLowerEqualTo : public SingleValuePredicateParam<size_t> {
- using Base::Base;
-};
-
-/// Indicates that the bit width of the elemental type must be equal to the give
-/// value.
-struct ElementTypeBitWidth : public SingleValuePredicateParam<size_t> {
- using Base::Base;
-};
-
-/// Predicate tag indicating that the affine map is a permutation.
-struct IsPermutation {};
-
-/// Predicate tag indicating that the affine map is a projected permutation.
-struct IsProjectedPermutation {};
-
-/// Predicate tag indicating that the affine map is a projection of given
-/// dimension.
-struct IsProjected : public SingleValuePredicateParam<int64_t> {
- using Base::Base;
-};
-/// Predicate tag indicating that the affine map is an identity.
-struct IsIdentity {};
-
-/// Predicate tag indicating that the operand is a special float constant.
-struct ConstantFloatMinOrMinusInf {};
-struct ConstantFloatZero {};
-struct ConstantFloatOne {};
-
-/// Indicates that the match optional. The matcher is still expected to run and
-/// capture if successful. The parameter can be set to false
-struct OptionalMatch : public SingleValuePredicateParam<bool> {
- OptionalMatch() : Base(true) {}
- explicit OptionalMatch(bool set) : Base(set) {}
-};
-
-/// Predicate tag indicating that the reduction is produced by a single combiner
-/// operation.
-struct SingleCombinerReduction {};
-
-class CapturingOpMatcher;
-class CapturingValueMatcher;
-
-/// Base class for capturing matchers that can be owned by the context.
-class CapturingMatcherBase {
-public:
- // Virtual destructor so unique pointers are deallocated correctly.
- // TODO: if efficiency is a problem, consider disallowing non-trivial
- // destructors for subclasses.
- virtual ~CapturingMatcherBase() = default;
-
-protected:
- /// Informs the matcher that it has another, nested matcher. Derived classes
- /// must call this to keep track of nested matchers for capture resetting
- /// purposes.
- template <typename T>
- void recordNestedMatcher(T &nested) {
- if constexpr (std::is_base_of_v<CapturingOpMatcher, T>) {
- nestedCapturingMatchers.push_back(&nested);
- }
- if constexpr (std::is_base_of_v<CapturingValueMatcher, T>) {
- nestedCapturingValueMatchers.push_back(&nested);
- }
- }
-
- /// Appends all nested capturing matchers of a certain kind, excluding this
- /// one, to `nested`.
- void getAllNested(SmallVectorImpl<CapturingOpMatcher *> &nested);
- void
- getAllNestedValueMatchers(SmallVectorImpl<CapturingValueMatcher *> &nested);
-
- /// Resets nested capturing matchers but does NOT reset the current one.
- void resetCapture();
-
-private:
- /// A list of (recursively) nested capturing matchers that should be reset
- /// when the current matcher is.
- SmallVector<CapturingOpMatcher *, 2> nestedCapturingMatchers;
- SmallVector<CapturingValueMatcher *, 2> nestedCapturingValueMatchers;
-};
-
-/// A context object holding capturing matchers, must outlive any individual
-/// matcher. When matching complex subgraphs, the caller often doesn't care
-/// about all intermediate nodes (operations) in the graph and shouldn't need to
-/// hold matcher objects for those. These matchers can be created in this
-/// context.
-class MatcherContext {
-public:
- /// Create a new matcher of the specified type owned by this context.
- template <typename T, typename... Args>
- std::enable_if_t<std::is_base_of_v<CapturingMatcherBase, T>, T> &
- allocate(Args &&...args) {
- // Need to call "new" explicitly as make_unique wouldn't have access to the
- // private constructor when this class would.
- ownedMatchers.emplace_back(
- std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
- return *static_cast<T *>(ownedMatchers.back().get());
- }
-
-private:
- /// Owning list of matchers.
- // TODO: If this becomes inefficient, consider something like BumpPtrAllocator
- // that derived classes can use to store their members as well.
- SmallVector<std::unique_ptr<CapturingMatcherBase>> ownedMatchers;
-};
-
-/// Base class for value matchers that capture the matched value. Stores a list
-/// of predicates and requires all of them to match for the value to match. Once
-/// a value matched, any repeated use just verifies that equality of the value.
-class CapturingValueMatcher : public CapturingMatcherBase {
- friend class CapturingMatcherBase;
- friend class MatcherContext;
-
- using PredicateFn = std::function<bool(Value)>;
-
-public:
- /// Resets the captured value to null. This should be called if the same
- /// pattern needs to be applied more than once as it may keep captured values
- /// for optional nested predicates from the previous application.
- void resetCapture() {
- captured = nullptr;
- CapturingMatcherBase::resetCapture();
- }
-
- /// Returns the matched value if the match was successful.
- Value getCaptured() const { return captured; }
-
- /// Matches the given value, hook for `matchPattern`.
- bool match(Value value);
-
-protected:
- CapturingValueMatcher() = default;
-
- /// Adds a predicate to the end of the predicate list for this value matcher.
- template <typename Fn>
- void addPredicate(Fn &&predicate) {
- predicates.emplace_back(std::forward<Fn>(predicate));
- }
-
- /// The captured value.
- Value captured = nullptr;
-
-private:
- /// Additional predicates to be checked on the value.
- SmallVector<PredicateFn> predicates;
-};
-
-/// Creates a matcher of an arbitrary value.
-inline CapturingValueMatcher &m_Value(MatcherContext &context) {
- return context.allocate<CapturingValueMatcher>();
-}
-
-/// Matcher for typed values whose type implements the `ShapedType` interface.
-/// Allows for matching the components of the shaped type such as rank and
-/// dimensions.
-class ShapedValueMatcher : public CapturingValueMatcher {
- friend class MatcherContext;
-
- ShapedValueMatcher();
-
-public:
- /// Add an always-succeeding matcher predicate capturing the rank.
- ShapedValueMatcher &rank(CaptureRank capture);
-
- /// Add an always-succeeding matcher predicate capturing the size of the
- /// dimension identified by the first argument.
- ShapedValueMatcher &dim(int64_t dimension, CaptureDim capture);
-
- /// Add an always-succeeding matcher predicate capturing the sizes of all
- /// dimensions in order of appearance.
- ShapedValueMatcher &dim(AllDims tag, CaptureDims captures);
-
- /// Add an always-succeeding matcher predicate capturing the element type of
- /// the value.
- ShapedValueMatcher &elementType(CaptureElementType captures);
-};
-
-/// Construct a new matcher of a value whose type is a `ShapedType`, owned by
-/// the given context.
-inline ShapedValueMatcher &m_ShapedValue(MatcherContext &context) {
- return context.allocate<ShapedValueMatcher>();
-}
-
-/// Matcher for operations with additional predicates attachable through the
-/// fluent, a.k.a. chainable, API. Note that public API must *not* accept
-/// additional callbacks even; new predicates should be added instead when
-/// necessary. Not only this decreases the depth of the callback stack and
-/// increases readability, it also allows us to port the matcher to a
-/// declarative format using PDL and/or Transform dialect in the future. The
-/// latter will become impossible with arbitrary C++ callbacks.
-class CapturingOpMatcher : public CapturingMatcherBase {
- friend class CapturingMatcherBase;
- friend class MatcherContext;
-
- template <typename... OpTy>
- friend CapturingOpMatcher &m_Operation(MatcherContext &matcherContext);
-
-public:
- using PredicateFn = std::function<bool(Operation *)>;
-
- /// Matches the given operation, hook for `matchPattern`.
- bool match(Operation *op);
-
- /// Resets the captured value to null. This should be called if the same
- /// pattern needs to be applied more than once as it may keep captured values
- /// for optional nested predicates from the previous application.
- void resetCapture() {
- captured = nullptr;
- CapturingMatcherBase::resetCapture();
- }
-
- /// Returns the matched operation if the match was successful.
- Operation *getCaptured() const { return captured; }
-
- /// Adds alternative paths for predicates. In practice, this is just a
- /// predicate that is satisfied when either the first or the second matcher is
- /// satisfied. The alternative satisfaction is eager and short-cutting, i.e.,
- /// the second alternative will not be processed, and therefore will not
- /// capture values, if the first alternative succeeded.
- CapturingOpMatcher &alternatives(CapturingOpMatcher &first,
- CapturingOpMatcher &second);
-
- //===-------------------------------------------------------------------===//
- // Constraints on adjacent ops.
- //===-------------------------------------------------------------------===//
-
- /// Adds a predicate checking that all ops implementing TilingInterface in the
- /// parent of the given type (e.g., a function or a module) were matched by
- /// this or nested matchers. This is useful to ensure that the matcher covered
- /// the entire parent region, not just a parent of it. This predicate **must**
- /// be added *after* all the other predicates that capture.
- template <typename OpTy>
- CapturingOpMatcher &allTilableOpsCaptured() {
- SmallVector<CapturingOpMatcher *> copy;
- copy.push_back(this);
- getAllNested(copy);
- addPredicate([copy = std::move(copy)](Operation *op) {
- Operation *parent = op->getParentOfType<OpTy>();
- return checkAllTilableMatched(parent, op, copy);
- });
- return *this;
- }
-
- //-------------------------------------------------------------------------//
- // Predicates for operands and results.
- //-------------------------------------------------------------------------//
-
- /// Adds a predicate checking that the operation has exactly the given number
- /// of operands.
- CapturingOpMatcher &operand(NumEqualsTo num);
-
- /// Adds a predicate checking that the `pos`-th operand of the operation is
- /// defined by an operation that satisfies the given matcher.
- CapturingOpMatcher &operand(int64_t pos, CapturingOpMatcher &nested);
-
- /// Adds a predicate checking that the `pos`-th operand of the operation
- /// satisfies the given value matcher.
- CapturingOpMatcher &operand(int64_t pos, CapturingValueMatcher &nested);
-
- /// Adds a predicate checking that the `pos`-th operand of the operation is
- /// defined by `arith.constant` with the value 1.0.
- // TODO: better matching for attributes.
- CapturingOpMatcher &operand(int64_t pos, ConstantFloatOne);
-
- /// Adds a predicate checking that the operation has exactly the given number
- /// of results.
- CapturingOpMatcher &result(NumEqualsTo num);
-
- /// Adds a predicate checking that the `pos`-th result of the operation
- /// satisfies the given value matcher.
- CapturingOpMatcher &result(int64_t pos, CapturingValueMatcher &nested);
-
-protected:
- /// Constructs a default operation matcher accepting any operation.
- CapturingOpMatcher() = default;
-
- /// Adds a predicate for the matched operation to satisfy.
- template <typename Fn>
- void addPredicate(Fn &&predicate) {
- predicates.emplace_back(std::forward<Fn>(predicate));
- }
-
- /// Produce the debug output for `create` method in a non-templated way.
- static void debugOutputForCreate(ArrayRef<StringRef> opNames);
-
-private:
- /// A list of additional conditions for the operation to match.
- SmallVector<PredicateFn> predicates;
-
- /// Checks that `matchers` captured all tilable ops nested in `parent` except
- /// for `linalgOp`. This is an implementation detail of allTilableOpsCaptured.
- static bool checkAllTilableMatched(Operation *parent, Operation *op,
- ArrayRef<CapturingOpMatcher *> matchers);
-
- /// Creates a matcher for an operation with one of the given types.
- template <typename... OpType>
- static CapturingOpMatcher create() {
- CapturingOpMatcher matcher;
- matcher.addPredicate([](Operation *op) {
- debugOutputForCreate(ArrayRef<StringRef>{OpType::getOperationName()...});
- return isa<OpType...>(op);
- });
- return matcher;
- }
-
- /// Common util for constant matcher.
- CapturingOpMatcher &operand(int64_t position,
- std::function<bool(llvm::APFloat)> floatValueFn);
-
-protected:
- /// Matched value.
- Operation *captured = nullptr;
-};
-
-namespace detail {
-/// Prints the debug output from the ConcreteOpMatcher constructor. The
-/// implementation must reside in the C++ file so we don't pollute the header
-/// with debug includes, and ConcreteOpMatcher is a class template that can only
-/// reside in the header.
-void debugOutputForConcreteOpMatcherConstructor(StringRef name);
-} // namespace detail
-
-/// Base class for matchers that match a specific op. Adds an initial predicate
-/// checking if the op is indeed of the specified kind.
-/// Derived classes specializing this for op interfaces MUST also define a
-/// specialization of DebugOpKindDescription.
-template <typename Derived, typename OpTy>
-class ConcreteOpMatcher : public CapturingOpMatcher {
-protected:
- using Base = ConcreteOpMatcher;
-
- static StringRef getConcreteOpDescription() {
- return OpTy::getOperationName();
- }
-
- /// Adds a predicate checking if the op is of the OpTy kind.
- ConcreteOpMatcher() {
- CapturingOpMatcher::addPredicate([](Operation *op) {
- detail::debugOutputForConcreteOpMatcherConstructor(
- Derived::getConcreteOpDescription());
- return isa<OpTy>(op);
- });
- }
-
- /// Adds a predicate for the matched operation to satisfy.
- template <typename FnTy>
- Derived &addPredicate(FnTy &&predicate) {
- // Dispatch to the callback.
- CapturingOpMatcher::addPredicate(
- [inner = std::move(predicate)](Operation *op) {
- return inner(cast<OpTy>(op));
- });
- return static_cast<Derived &>(*this);
- }
-
-public:
- /// Adds alternative paths for predicates. In practice, this is just a
- /// predicate that is satisfied when either the first or the second matcher is
- /// satisfied. The alternative satisfaction is eager and short-cutting, i.e.,
- /// the second alternative will not be processed, and therefore will not
- /// capture values, if the first alternative succeeded.
- Derived &alternatives(CapturingOpMatcher &first, CapturingOpMatcher &second) {
- return static_cast<Derived &>(
- CapturingOpMatcher::alternatives(first, second));
- }
-
- /// Adds a predicate checking that all ops implementing TilingInterface in the
- /// parent of the given type (e.g., a function or a module) were matched by
- /// this or nested matchers. This is useful to ensure that the matcher covered
- /// the entire parent region, not just a parent of it. This predicate **must**
- /// be added *after* all the other predicates that capture.
- template <typename ParentTy>
- Derived &allTilableOpsCaptured() {
- return static_cast<Derived &>(
- CapturingOpMatcher::allTilableOpsCaptured<ParentTy>());
- }
-
- //-------------------------------------------------------------------------//
- // Predicates for operands and results.
- //-------------------------------------------------------------------------//
-
- /// Adds a predicate checking that the operation has exactly the given number
- /// of operands.
- Derived &operand(NumEqualsTo num) {
- return static_cast<Derived &>(CapturingOpMatcher::operand(num));
- }
-
- /// Adds a predicate checking that the `pos`-th operand of the operation is
- /// defined by an operation that satisfies the given matcher.
- Derived &operand(int64_t pos, CapturingOpMatcher &nested) {
- return static_cast<Derived &>(CapturingOpMatcher::operand(pos, nested));
- }
-
- /// Adds a predicate checking that the `pos`-th operand of the operation
- /// satisfies the given value matcher.
- Derived &operand(int64_t pos, CapturingValueMatcher &nested) {
- return static_cast<Derived &>(CapturingOpMatcher::operand(pos, nested));
- }
-
- /// Adds a predicate checking that the `pos`-th operand of the operation is
- /// defined by `arith.constant` with the value 1.0.
- // TODO: better matching for attributes.
- Derived &operand(int64_t pos, ConstantFloatOne c) {
- return static_cast<Derived &>(CapturingOpMatcher::operand(pos, c));
- }
-
- /// Adds a predicate checking that the operation has exactly the given number
- /// of results.
- Derived &result(NumEqualsTo num) {
- return static_cast<Derived &>(CapturingOpMatcher::result(num));
- }
-
- /// Adds a predicate checking that the `pos`-th result of the operation
- /// satisfies the given value matcher.
- Derived &result(int64_t pos, CapturingValueMatcher &nested) {
- return static_cast<Derived &>(CapturingOpMatcher::result(pos, nested));
- }
-};
-
-/// Matcher for the `tensor.pad` operation.
-class TensorPadOpMatcher
- : public ConcreteOpMatcher<TensorPadOpMatcher, tensor::PadOp> {
- friend class MatcherContext;
-
- TensorPadOpMatcher() = default;
-
-public:
- /// Adds a predicate checking that the low padding sizes are exactly the given
- /// values.
- TensorPadOpMatcher &low(ArrayRef<int64_t> sizes);
-
- /// Adds a predicate checking that the low padding sizes for all dimensions
- /// are exactly the same given value.
- TensorPadOpMatcher &low(AllDims tag, int64_t size);
-
- /// Adds a predicate checking that the high padding sizes for all dimensions
- /// are exactly the same given value.
- TensorPadOpMatcher &high(ArrayRef<int64_t> sizes);
-
- /// Adds a predicate checking that the high padding sizes for all dimensions
- /// are exactly the same given value.
- TensorPadOpMatcher &high(AllDims tag, int64_t size);
-
- /// Adds a predicate checking that the body of the pad only yields values
- /// defined outside the pad region.
- TensorPadOpMatcher &yieldsExternalValue();
-};
-
-inline TensorPadOpMatcher &m_tensorPad(MatcherContext &matcherContext) {
- return matcherContext.allocate<TensorPadOpMatcher>();
-}
-
-/// Creates a default operation matcher in the given context that accepts any
-/// operation.
-inline CapturingOpMatcher &m_Operation(MatcherContext &matcherContext) {
- return matcherContext.allocate<CapturingOpMatcher>();
-}
-
-/// Creates an operation matcher in the given context that accepts only
-/// operations of the kinds provided as template arguments.
-template <typename... OpTy>
-inline CapturingOpMatcher &m_Operation(MatcherContext &matcherContext) {
- return matcherContext.allocate<CapturingOpMatcher>(
- CapturingOpMatcher::create<OpTy...>());
-}
-
-/// Matcher for structured aka Linalg operations.
-class StructuredOpMatcher
- : public ConcreteOpMatcher<StructuredOpMatcher, linalg::LinalgOp> {
- friend class MatcherContext;
-
- StructuredOpMatcher() = default;
-
-public:
- static StringRef getConcreteOpDescription() {
- return "linalg interface implementation";
- }
-
- /// Creates a matcher for a structured operation with one of the given types.
- template <typename... OpType>
- static StructuredOpMatcher create() {
- StructuredOpMatcher matcher;
- matcher.addPredicate([](Operation *op) {
- debugOutputForCreate(ArrayRef<StringRef>{OpType::getOperationName()...});
- return isa<linalg::LinalgOp>(op) && isa<OpType...>(op);
- });
- return matcher;
- }
-
- /// Matches a structured operation if either patterns A or B match.
- StructuredOpMatcher(StructuredOpMatcher &A, StructuredOpMatcher &B);
-
- //===-------------------------------------------------------------------===//
- // Constraints on op rank and dims.
- //===-------------------------------------------------------------------===//
- /// Adds a predicate checking that the given rank must be greater than some
- /// constant value.
- StructuredOpMatcher &rank(NumGreaterEqualTo minRank);
- StructuredOpMatcher &rank(NumLowerEqualTo maxRank);
- StructuredOpMatcher &rank(NumEqualsTo exactRank);
-
- /// Adds a predicate checking that the given iteration space dimension is
- /// static/dynamic. The dimension index may be negative, in which case
- /// dimensions are counted from the last one (i.e. Python-style), or be an
- /// AllDims tag, in which case all dimensions are checked. This may be
- /// eventually extended to slices and/or lists of dimensions.
- StructuredOpMatcher &dim(int64_t dimension, ShapeKind kind) {
- return dim(SmallVector<int64_t>{dimension}, kind);
- }
- StructuredOpMatcher &dim(SmallVector<int64_t> &&dimensions, ShapeKind kind);
- StructuredOpMatcher &dim(AllDims tag, ShapeKind kind);
-
- /// Adds a predicate checking that the given iteration space dimension has the
- /// given iterator type, e.g., parallel or reduction. The dimension index may
- /// be negative, in which case dimensions are counted from the last one
- /// (i.e. Python-style), or be an AllDims tag, in which case all dimensions
- /// are checked. This may be eventually extended to slices and/or lists of
- /// dimensions.
- StructuredOpMatcher &dim(int64_t dimension, utils::IteratorType kind) {
- return dim(SmallVector<int64_t>{dimension}, kind);
- }
- // Ownership may get tricky here so we wrap in an explicit vector.
- StructuredOpMatcher &dim(SmallVector<int64_t> &&dimensions,
- utils::IteratorType kind);
- StructuredOpMatcher &dim(AllDims tag, utils::IteratorType kind);
- StructuredOpMatcher &dim(AllDimsExcept &&dimensions,
- utils::IteratorType kind);
-
- /// Adds a predicate checking that the given iteration space dimension is
- /// statically known to be divisible by the given value. The dimension index
- /// may be negative, in which case dimensions are counted from the last one
- /// (i.e. Python-style).
- StructuredOpMatcher &dim(int64_t dimension, DivisibleBy divisibleBy);
-
- //===-------------------------------------------------------------------===//
- // Capture directives.
- //===-------------------------------------------------------------------===//
- StructuredOpMatcher &rank(CaptureRank capture);
- StructuredOpMatcher &dim(int64_t dimension, CaptureDim capture);
- StructuredOpMatcher &dim(AllDims tag, CaptureDims captures);
- StructuredOpMatcher &indexingMaps(CaptureIndexingMaps indexingMaps);
- StructuredOpMatcher &contractionDims(CaptureContractionDims contractionDims);
- StructuredOpMatcher &convolutionDims(CaptureConvDims convDims);
-
- //===-------------------------------------------------------------------===//
- // Constraints on input operands.
- //===-------------------------------------------------------------------===//
- /// Adds a predicate checking that the structured op has the given number of
- /// inputs.
- StructuredOpMatcher &input(NumEqualsTo num);
-
- /// Adds a predicate that recursively applies other predicates to the
- /// operation defining the `position`-th operand. The position may be
- /// negative, in which case positions are counted from the last one
- /// (i.e. Python-style). When the match is optional, the predicate check
- /// succeeds as long as the `position` is in bounds. The matcher is executed
- /// if there is a defining operation for the input operand.
- template <typename T>
- std::enable_if_t<llvm::is_detected<::mlir::detail::has_compatible_matcher_t,
- T, Operation *>::value,
- StructuredOpMatcher &>
- input(int64_t position, T &operandMatcher,
- OptionalMatch optional = OptionalMatch(false)) {
- addInputMatcher(
- position,
- [&operandMatcher](Operation *op) { return operandMatcher.match(op); },
- optional);
- recordNestedMatcher(operandMatcher);
- return *this;
- }
- template <typename T>
- std::enable_if_t<llvm::is_detected<::mlir::detail::has_compatible_matcher_t,
- T, Value>::value,
- StructuredOpMatcher &>
- input(int64_t position, T &operandMatcher,
- OptionalMatch optional = OptionalMatch(false)) {
- addInputMatcher(
- position,
- [&operandMatcher](Value v) { return operandMatcher.match(v); },
- optional);
- recordNestedMatcher(operandMatcher);
- return *this;
- }
-
- /// Adds a predicate checking that all input operands of the structured op
- /// have a permutation indexing map.
- StructuredOpMatcher &input(AllOperands tag, IsPermutation);
-
- /// Adds a predicate checking that all input operands of the structured op
- /// have a projected permutation indexing map.
- StructuredOpMatcher &input(AllOperands tag, IsProjectedPermutation);
-
- /// Adds a predicate checking that all input operands of the structured op
- /// are projected along the given dimension.
- StructuredOpMatcher &input(SmallVector<int64_t> &&positions, IsProjected dim);
- StructuredOpMatcher &input(int64_t position, IsProjected dim) {
- return input(SmallVector<int64_t>{position}, dim);
- }
-
- /// Adds a predicate checking that all input operands of the structured op
- /// have identity indexing map.
- StructuredOpMatcher &input(AllOperands tag, IsIdentity);
- StructuredOpMatcher &input(SmallVector<int64_t> &&positions, IsIdentity);
- StructuredOpMatcher &input(int64_t position, IsIdentity) {
- return input(SmallVector<int64_t>{position}, IsIdentity());
- }
-
- /// Adds a predicate checking that the bit width of the elemental type of the
- /// structured op input at the given position is equal to the given value.
- StructuredOpMatcher &input(int64_t position, ElementTypeBitWidth width);
-
- /// Capture the elemental type bitwidth of input operand `position`.
- StructuredOpMatcher &input(int64_t position,
- CaptureElementTypeBitWidth width);
-
- /// Capture the elemental type of input operand `position`.
- StructuredOpMatcher &input(int64_t position, CaptureElementType elem);
-
- /// Check if input is equal to a known constant.
- // TODO: Support matching for constant ops.
- StructuredOpMatcher &input(int64_t position, ConstantFloatMinOrMinusInf);
- StructuredOpMatcher &input(int64_t position, ConstantFloatZero);
-
- //===-------------------------------------------------------------------===//
- // Constraints on output operands.
- //===-------------------------------------------------------------------===//
-
- /// Adds a predicate checking that the structured op has the given number of
- /// outputs.
- StructuredOpMatcher &output(NumEqualsTo num);
-
- /// Adds a predicate checking that all output operands of the structured op
- /// have a permutation indexing map.
- StructuredOpMatcher &output(AllOperands tag, IsPermutation);
-
- /// Adds a predicate checking that all output operands of the structured op
- /// have a projected permutation indexing map.
- StructuredOpMatcher &output(AllOperands tag, IsProjectedPermutation);
-
- /// Adds a predicate checking that all output operands of the structured op
- /// have a
- StructuredOpMatcher &output(AllOperands tag, IsProjected dim);
-
- /// Adds a predicate checking that all output operands of the structured op
- /// have identity indexing map.
- StructuredOpMatcher &output(AllOperands tag, IsIdentity);
-
- /// Adds a predicate checking that the bit width of the elemental type of the
- /// structured op output at the given position is equal to the given value.
- StructuredOpMatcher &output(int64_t position, ElementTypeBitWidth width);
-
- /// Capture the elemental type bitwidth of output operand `position`.
- StructuredOpMatcher &output(int64_t position,
- CaptureElementTypeBitWidth width);
-
- /// Capture the elemental type of output operand `position`.
- StructuredOpMatcher &output(int64_t position, CaptureElementType elem);
-
- /// Adds a predicate checking that the output of the structured op is produced
- /// by a reduction with a single-operation combinator (such as addf or mulf,
- /// but not a compare+select pair).
- StructuredOpMatcher &output(int64_t position, SingleCombinerReduction tag);
-
- /// Adds a predicate that recursively applies other predicates to the
- /// operation defining the init/out operand corresponding to `position`-th
- /// output. The position may be negative, in which case positions are counted
- /// from the last one (i.e. Python-style). When the match is optional, the
- /// predicate check succeeds as long as the `position` is in bounds. The
- /// matcher executed if there is a defining operation for the output operand.
- template <typename T>
- std::enable_if_t<llvm::is_detected<::mlir::detail::has_compatible_matcher_t,
- T, Operation *>::value,
- StructuredOpMatcher &>
- output(int64_t position, T &operandMatcher,
- OptionalMatch optional = OptionalMatch(false)) {
- addOutputMatcher(
- position,
- [&operandMatcher](Operation *op) { return operandMatcher.match(op); },
- optional);
- recordNestedMatcher(operandMatcher);
- return *this;
- }
-
- //===-------------------------------------------------------------------===//
- // Constraints on results.
- //===-------------------------------------------------------------------===//
-
- /// Adds a predicate that recursively applies to users of the `position`-th
- /// result of the structured op. Succeeds if any user matches the predicate.
- /// When the match is optional, the predicate check succeeds as long as the
- /// `position` is in bounds, after running the given matcher.
- template <typename T>
- std::enable_if_t<llvm::is_detected<::mlir::detail::has_compatible_matcher_t,
- T, Operation *>::value,
- StructuredOpMatcher &>
- result(int64_t position, HasAnyUse tag, T &resultUserMatcher,
- OptionalMatch optional = OptionalMatch(false)) {
- addResultMatcher(
- position, tag,
- [&resultUserMatcher](Operation *op) {
- return resultUserMatcher.match(op);
- },
- optional);
- recordNestedMatcher(resultUserMatcher);
- return *this;
- }
-
- //===-------------------------------------------------------------------===//
- // Constraints on op region.
- //===-------------------------------------------------------------------===//
-
- /// Return true if the linalg op only contains a single ops and the arguments
- /// of the operation match the order of the linalg operand.
- /// Example:
- /// linalg.generic
- /// ins(%0, %1 : tensor<?x?x?xf32>, tensor<?x?xf32>)
- /// outs(%2 : tensor<?x?x?xf32>) {
- /// ^bb0(%arg0: f32, %arg1: f32):
- /// %3 = arith.maxf %arg0, %arg1 : f32
- /// linalg.yield %3 : f32
- /// } -> tensor<?x?xf32>
- /// If commutative is set binary operations can have their operands swapped.
- template <typename OpType>
- StructuredOpMatcher &singleOpWithCanonicaleArgs(bool commutative = false) {
- return singleOpWithCanonicaleArgs(OpType::getOperationName(), commutative);
- }
- StructuredOpMatcher &singleOpWithCanonicaleArgs(StringRef opname,
- bool commutative);
- /// Check if the op is a linalg of with a single float reciprocal op.
- StructuredOpMatcher &isFloatReciprocal();
- /// Check if the op is a linalg of with a region containing only a yield op
- /// using block arguments in order.
- StructuredOpMatcher &passThroughOp();
-
- /// Check if the body of the linalg op implements a contraction of the kind
- /// result <ReductionOpTy>= input1 <ElemOpTy> input2
- template <typename ElemOpTy, typename ReductionOpTy>
- StructuredOpMatcher &hasContractionBody() {
- return hasContractionBody(
- [](Operation *op) { return isa<ElemOpTy>(op); },
- [](Operation *op) { return isa<ReductionOpTy>(op); },
- ElemOpTy::getOperationName(), ReductionOpTy::getOperationName());
- }
-
-private:
- /// Non-template implementations of nested predicate builders for inputs,
- /// outputs and results. Should not be called directly.
- void addInputMatcher(int64_t position,
- std::function<bool(Operation *)> matcher,
- OptionalMatch optional);
- void addInputMatcher(int64_t position, std::function<bool(Value)> matcher,
- OptionalMatch optional);
- void addOutputMatcher(int64_t position,
- std::function<bool(Operation *)> matcher,
- OptionalMatch optional);
- void addResultMatcher(int64_t position, HasAnyUse tag,
- std::function<bool(Operation *)> matcher,
- OptionalMatch optional);
-
- // Common util for constant matcher.
- StructuredOpMatcher &input(int64_t position,
- std::function<bool(llvm::APFloat)> floatValueFn);
-
- /// Non-template implementation of hasContractionBody. Takes callbacks for
- /// checking operation kinds and names for error reporting.
- StructuredOpMatcher &
- hasContractionBody(function_ref<bool(Operation *)> isaElemOpTy,
- function_ref<bool(Operation *)> isaReductionOpTy,
- StringRef elemOpName, StringRef reductionOpName);
-};
-
-/// Creates a matcher of an arbitrary structured op.
-inline StructuredOpMatcher &m_StructuredOp(MatcherContext &matcherContext) {
- return matcherContext.allocate<StructuredOpMatcher>();
-}
-
-/// Creates a matcher that is a copy of the given matcher.
-inline StructuredOpMatcher &m_StructuredOp(MatcherContext &matcherContext,
- const StructuredOpMatcher &other) {
- return matcherContext.allocate<StructuredOpMatcher>(other);
-}
-
-/// Creates a matcher that accepts as disjunction of the two given matchers.
-inline StructuredOpMatcher &m_StructuredOp_Or(MatcherContext &matcherContext,
- StructuredOpMatcher &A,
- StructuredOpMatcher &B) {
- return matcherContext.allocate<StructuredOpMatcher>(A, B);
-}
-
-/// Creates a matcher of a structured op with kinds provided as template
-/// arguments.
-template <typename... OpType>
-inline StructuredOpMatcher &m_StructuredOp(MatcherContext &matcherContext) {
- return matcherContext.allocate<StructuredOpMatcher>(
- StructuredOpMatcher::create<OpType...>());
-}
-
-//===---------------------------------------------------------------------===//
-// MatchCallback functionality.
-//===---------------------------------------------------------------------===//
-
-/// Additional results of the C++ callback usable in the `match_callback`
-/// transform operation. Conceptually, a list of lists of payload operations to
-/// be associated with each result handle.
-class MatchCallbackResult {
-public:
- /// Returns the number of lists of payload operations.
- int64_t getNumPayloadGroups() const { return payloadGroupLengths.size(); }
-
- /// Returns the `position`-th list of payload operations.
- ArrayRef<Operation *> getPayloadGroup(int64_t position) const;
-
- /// Adds a new list of payload operations to the list of lists. The new list
- /// must not contain null operations.
- template <typename Range>
- int64_t addPayloadGroup(Range operations) {
- int64_t originalLength = payloadOperations.size();
- assert(llvm::all_of(operations, [](Operation *op) -> bool { return op; }) &&
- "null operation");
- llvm::append_range(payloadOperations, operations);
- payloadGroupLengths.push_back(payloadOperations.size() - originalLength);
- return payloadGroupLengths.size() - 1;
- }
- void addPayloadGroup(ArrayRef<Operation *> operations) {
- addPayloadGroup<ArrayRef<Operation *>>(operations);
- }
-
- /// Adds a new singleton list of payload operation to the list of lists if the
- /// operation is non-null, adds an empty list otherwise. Useful for results of
- /// optional matches.
- void addPotentiallyEmptyPayloadGroup(Operation *op) {
- if (!op) {
- addPayloadGroup(ArrayRef<Operation *>());
- } else {
- addPayloadGroup(ArrayRef<Operation *>(op));
- }
- }
-
-private:
- /// The flat list of all payload operations. `payloadGroupLengths` can be used
- /// to compute the sublist that corresponds to one nested list.
- // TODO: if somebody implements such a flattened vector generically, use it.
- SmallVector<Operation *> payloadOperations;
- SmallVector<int64_t> payloadGroupLengths;
-};
-
-/// A transform state extension that maintains the mapping between callback
-/// names as strings usable in `match_callback` and their implementations.
-class MatchCallbacksRegistry : public transform::TransformState::Extension {
-public:
- using MatchCallbackFn = std::function<DiagnosedSilenceableFailure(
- MatchCallbackResult &, Location, const transform::TransformState &,
- ValueRange)>;
-
- /// Constructs the extension.
- MatchCallbacksRegistry(transform::TransformState &state)
- : transform::TransformState::Extension(state) {}
-
- /// Registers the given function as a callback with the given name. The name
- /// must not be already present in the registry. The callback must be
- /// convertible to MatchCallbackFn.
- template <typename Fn>
- void registerCallback(StringRef name, Fn &&fn) {
- bool succeeded = callbacks.try_emplace(name, std::forward<Fn>(fn)).second;
- (void)succeeded;
- assert(succeeded && "adding a callback with a repeated name");
- }
-
- /// Returns a pointer to the implementation of the callback with the given
- /// name, or null if it is not present in the registry.
- const MatchCallbackFn *get(StringRef name) const {
- auto iter = callbacks.find(name);
- if (iter == callbacks.end()) {
- return nullptr;
- }
- return &iter->getValue();
- }
-
-private:
- llvm::StringMap<MatchCallbackFn> callbacks;
-};
-
-//===---------------------------------------------------------------------===//
-// Case-specific matcher builders.
-//===---------------------------------------------------------------------===//
-
-struct MatchedReductionCaptures {
- int64_t reductionRank = 0;
- int64_t maybeLeadingRank = 0;
- int64_t maybeTrailingRank = 0;
- SmallVector<int64_t> leadingOpSizes = {};
- SmallVector<int64_t> reductionOpSizes = {};
- SmallVector<int64_t> trailingOpSizes = {};
- int64_t reductionOutputElementalTypeBitWidth = 0;
- int64_t maybeLeadingOutputElementalTypeBitWidth = 0;
- int64_t maybeTrailingOutputElementalTypeBitWidth = 0;
-};
-
-struct MatchedMatmulCaptures {
- linalg::ContractionDimensions contractionDims = {};
- Type lhsElementType, rhsElementType, outputElementType;
- SmallVector<int64_t> matmulOpSizes = {};
- SmallVector<AffineMap> indexingMaps;
-
- /// Helper functions.
- int64_t rank() const { return matmulOpSizes.size(); }
- /// Return all batches.
- ArrayRef<unsigned> batches() const { return contractionDims.batch; }
- /// Return the most minor candidate dimension for `m`.
- int64_t m() const { return contractionDims.m.back(); }
- /// Return the most minor candidate dimension for `n`.
- int64_t n() const { return contractionDims.n.back(); }
- /// Return the most minor candidate dimension for `k`.
- int64_t k() const { return contractionDims.k.back(); }
- /// AffineMap for indexing into the LHS.
- AffineMap lhsIndexing() const {
- assert(indexingMaps.size() == 3 && "expected 3 indexing maps");
- return indexingMaps[0];
- }
- /// AffineMap for indexing into the RHS.
- AffineMap rhsIndexing() const {
- assert(indexingMaps.size() == 3 && "expected 3 indexing maps");
- return indexingMaps[1];
- }
- /// AffineMap for indexing into the RES.
- AffineMap resIndexing() const {
- assert(indexingMaps.size() == 3 && "expected 3 indexing maps");
- return indexingMaps[2];
- }
-};
-
-/// Creates a group of matchers for:
-///
-/// trailing(reduction(leading(), fill()))
-///
-/// where trailing and leading are elementwise operations whose presence is
-/// optional. Each matcher will capture the corresponding operation. If
-/// `mustMatchEntireFunc` is set, the matcher additionally checks if all
-/// tileable operations in the functions are captured.
-void makeReductionMatcher(MatcherContext &context,
- StructuredOpMatcher *&reductionCapture,
- StructuredOpMatcher *&fillCapture,
- StructuredOpMatcher *&leadingCapture,
- StructuredOpMatcher *&trailingCapture,
- MatchedReductionCaptures &captures,
- bool mustMatchEntireFunc);
-void makeReductionMatcher(MatcherContext &context,
- StructuredOpMatcher *&reductionCapture,
- MatchedReductionCaptures &captures,
- bool mustMatchEntireFunc);
-///
-/// trailing(matmul(*, *, fill()))
-///
-/// where trailing and leading are elementwise operations whose presence is
-/// optional. Each matcher will capture the corresponding operation. If
-/// `mustMatchEntireFunc` is set, the matcher additionally checks if all
-/// tileable operations in the functions are captured.
-void makeMatmulMatcher(MatcherContext &matcherContext,
- StructuredOpMatcher *&matmulCapture,
- StructuredOpMatcher *&fillCapture,
- StructuredOpMatcher *&trailingCapture,
- MatchedMatmulCaptures &captures,
- bool mustMatchEntireFunc);
-
-/// Create a group of matchers of batch matmul with a fill:
-///
-/// batch_matmul(*, *, fill())
-///
-/// and capture various useful quantities. If `mustMatchEntireFunc` is set, the
-/// matcher additionally checks if all tileable operations in the functions are
-/// captured.
-void makeBatchMatmulMatcher(transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&bmmCapture,
- transform_ext::StructuredOpMatcher *&fillCapture,
- transform_ext::MatchedMatmulCaptures &captures,
- bool mustMatchEntireFunc);
-
-/// Create a group of matchers for a different code sequence of operations
-/// matching exactly a softmax operation.
-///
-/// %red = reduce_max(%0)
-/// %sub = sub(%0, %red)
-/// %exp = exp(%sub)
-/// %sum = reduce_sum(%exp)
-/// %mul = div(%exp, %%sum)
-void makeSoftmaxMatcher(MatcherContext &context,
- StructuredOpMatcher *&maxReductionCapture,
- StructuredOpMatcher *&softmaxRootCapture);
-
-struct MatchedConvolutionCaptures {
- Type inputElementType, filterElementType, outputElementType;
- mlir::linalg::ConvolutionDimensions convolutionDims = {};
- SmallVector<int64_t> convolutionOpSizes = {};
- SmallVector<int64_t> trailingOpSizes = {};
- int64_t maybeTrailingOutputElementalTypeBitWidth = 0;
- int64_t maybeFillElementalTypeBitWidth = 0;
-};
-
-/// Creates a group of matchers for:
-///
-/// trailing(convolution(input, filter, fill()))
-///
-/// where fill is a FillOp and trailing is an elementwise operation, both of
-/// which is optional. Each matcher will capture the corresponding operation. If
-/// `mustMatchEntireFunc` is set, the matcher additionally checks if all
-/// tileable operations in the functions are captured.
-void makeConvolutionMatcher(MatcherContext &context,
- StructuredOpMatcher *&convolutionCapture,
- StructuredOpMatcher *&fillCapture,
- StructuredOpMatcher *&trailingCapture,
- MatchedConvolutionCaptures &captures,
- bool mustMatchEntireFunc);
-void makeConvolutionMatcher(MatcherContext &context,
- StructuredOpMatcher *&convolutionCapture,
- MatchedConvolutionCaptures &captures,
- bool mustMatchEntireFunc);
-
-struct MatchedPadCaptures {
- int64_t rank = 0;
- Type elementType;
- SmallVector<int64_t> dims = {};
-};
-
-/// Create a matcher for tensor.pad(*) without leading or trailing ops atm.
-/// If `mustMatchEntireFunc` is set, the matcher additionally checks if all
-/// tileable operations in the functions are captured.
-void makePadMatcher(MatcherContext &context, CapturingOpMatcher *&padCapture,
- MatchedPadCaptures &captures, bool mustMatchEntireFunc);
-
-/// Wraps the given matcher callback to indicate that it must capture all
-/// tilable ops in the parent function. Expects the callback to accept the same
-/// arguments as what is expected by MatchCallbacksRegistry::register, followed
-/// by a bool.
-template <typename Fn>
-auto wrapAsEntireFuncMatch(Fn &&fn) {
- return [fn = std::move(fn)](MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- return fn(res, loc, state, handles, true);
- };
-}
-
-/// Wraps the given matcher callback to indicate that it can match subgraphs.
-/// Expects the callback to accept the same arguments as what is expected by
-/// MatchCallbacksRegistry::register, followed by a bool.
-template <typename Fn>
-auto wrapAsPartialMatch(Fn &&fn) {
- return [fn = std::move(fn)](MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- return fn(res, loc, state, handles, false);
- };
-}
-
-} // namespace transform_ext
-} // namespace mlir
-
-#endif // IREE_COMPILER_CODEGEN_COMMON_TRANSFORMEXTENSIONS_TRANSFORMMATCHERS_H_
diff --git a/llvm-external-projects/iree-dialects/lib/CAPI/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/CAPI/CMakeLists.txt
deleted file mode 100644
index 9ed9512..0000000
--- a/llvm-external-projects/iree-dialects/lib/CAPI/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-add_mlir_public_c_api_library(IREEDialectsCAPI
- Dialects.cpp
- LINK_LIBS PUBLIC
- IREELinalgTransformDialect
- MLIRIR
- MLIRLinalgTransformOps
- MLIRTransformDialect
-)
-
-iree_dialects_target_includes(IREEDialectsCAPI)
diff --git a/llvm-external-projects/iree-dialects/lib/CAPI/Dialects.cpp b/llvm-external-projects/iree-dialects/lib/CAPI/Dialects.cpp
deleted file mode 100644
index 3bcb0b0..0000000
--- a/llvm-external-projects/iree-dialects/lib/CAPI/Dialects.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2021 The IREE Authors
-//
-// Licensed 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
-
-#include "iree-dialects-c/Dialects.h"
-
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
-#include "mlir/CAPI/IR.h"
-#include "mlir/CAPI/Pass.h"
-#include "mlir/CAPI/Registration.h"
-#include "mlir/CAPI/Support.h"
-#include "mlir/CAPI/Utils.h"
-#include "mlir/CAPI/Wrap.h"
-#include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
-#include "mlir/Dialect/Transform/IR/TransformDialect.h"
-#include "mlir/Support/LLVM.h"
-
-using namespace mlir;
-
-//===--------------------------------------------------------------------===//
-// TransformDialect
-//===--------------------------------------------------------------------===//
-
-void ireeRegisterTransformExtensions(MlirContext context) {
- MLIRContext *ctx = unwrap(context);
- DialectRegistry registry;
- registry
- .addExtensions<mlir::transform_ext::StructuredTransformOpsExtension>();
- ctx->appendDialectRegistry(registry);
-}
diff --git a/llvm-external-projects/iree-dialects/lib/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/CMakeLists.txt
index 76b98c3..e69de29 100644
--- a/llvm-external-projects/iree-dialects/lib/CMakeLists.txt
+++ b/llvm-external-projects/iree-dialects/lib/CMakeLists.txt
@@ -1,3 +0,0 @@
-add_subdirectory(CAPI)
-add_subdirectory(Dialect)
-add_subdirectory(Transforms)
diff --git a/llvm-external-projects/iree-dialects/lib/Dialect/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/Dialect/CMakeLists.txt
deleted file mode 100644
index 1da2860..0000000
--- a/llvm-external-projects/iree-dialects/lib/Dialect/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(LinalgTransform)
diff --git a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/CMakeLists.txt
deleted file mode 100644
index f33061b..0000000
--- a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(IR)
diff --git a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/CMakeLists.txt
deleted file mode 100644
index 6eb51d3..0000000
--- a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-add_mlir_library(IREELinalgTransformDialect
- StructuredTransformOpsExt.cpp
-
- DEPENDS
- mlir-headers
-
- LINK_LIBS PUBLIC
- IREEDialectsTransforms
- MLIRIR
-
- MLIRAsyncDialect
- MLIRControlFlowInterfaces
- MLIRLinalgDialect
- MLIRPDLDialect
- MLIRRewrite
- MLIRTransformDialect
- MLIRTransformDialectInterfaces
- MLIRTransformPDLExtension
-
- # Transforms
- MLIRAffineToStandard
- MLIRAsyncTransforms
- MLIRLinalgTransforms
- MLIRMemRefTransforms
- MLIRReconcileUnrealizedCasts
- MLIRTensorTransformOps
- MLIRTransforms
- MLIRVectorToSCF
-
- # Conversions
- MLIRAsyncToLLVM
- MLIRIndexToLLVM
- MLIRMathToLLVM
- MLIRMemRefToLLVM
- MLIRSCFToControlFlow
- MLIRVectorToLLVM
- MLIRVectorToLLVMPass
-)
diff --git a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/StructuredTransformOpsExt.cpp b/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/StructuredTransformOpsExt.cpp
deleted file mode 100644
index 6f9ae25..0000000
--- a/llvm-external-projects/iree-dialects/lib/Dialect/LinalgTransform/IR/StructuredTransformOpsExt.cpp
+++ /dev/null
@@ -1,999 +0,0 @@
-// Copyright 2022 The IREE Authors
-//
-// Licensed 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
-
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
-
-#include "iree-dialects/Transforms/TransformMatchers.h"
-#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"
-#include "mlir/Conversion/AsyncToLLVM/AsyncToLLVM.h"
-#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h"
-#include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h"
-#include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h"
-#include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
-#include "mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h"
-#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
-#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
-#include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
-#include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVMPass.h"
-#include "mlir/Conversion/VectorToSCF/VectorToSCF.h"
-#include "mlir/Dialect/Affine/IR/AffineOps.h"
-#include "mlir/Dialect/Affine/LoopUtils.h"
-#include "mlir/Dialect/Async/Passes.h"
-#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
-#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
-#include "mlir/Dialect/Linalg/Passes.h"
-#include "mlir/Dialect/Linalg/Transforms/Hoisting.h"
-#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
-#include "mlir/Dialect/MemRef/Transforms/Passes.h"
-#include "mlir/Dialect/SCF/Transforms/Transforms.h"
-#include "mlir/Dialect/SCF/Utils/Utils.h"
-#include "mlir/Dialect/Transform/IR/TransformDialect.h"
-#include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h"
-#include "mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h"
-#include "mlir/Interfaces/FunctionInterfaces.h"
-#include "mlir/Pass/PassManager.h"
-#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
-#include "mlir/Transforms/LoopInvariantCodeMotionUtils.h"
-#include "mlir/Transforms/Passes.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/TypeSwitch.h"
-#include "llvm/Support/Debug.h"
-
-#define DEBUG_TYPE "transform-ops-ext"
-#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
-
-using namespace mlir;
-
-//===----------------------------------------------------------------------===//
-// Additional constraints for PDLMatchOp.
-//===----------------------------------------------------------------------===//
-
-/// Hook for PDL driver to check if an operation (`pdlValues[0]`) is directly
-/// nested in a function with the name provided by an attribute
-/// (`pdlValues[1]`).
-/// TODO: PDL needs user-defined "questions".
-static LogicalResult nestedInFunc(PatternRewriter &rewriter,
- PDLResultList &pdlResults,
- ArrayRef<PDLValue> pdlValues) {
- assert(pdlValues.size() == 2 && "expected 2 PDL values");
- Operation *operation = pdlValues[0].cast<Operation *>();
- Attribute attr = pdlValues[1].cast<Attribute>();
-
- auto func = operation->getParentOfType<mlir::FunctionOpInterface>();
- if (!func) {
- return rewriter.notifyMatchFailure(operation, "not nested in a function");
- }
- auto functionSymbol = dyn_cast<SymbolRefAttr>(attr);
- if (!functionSymbol) {
- return rewriter.notifyMatchFailure(operation, "not a function identifier");
- }
- return success(functionSymbol.getLeafReference() == func.getName());
-}
-
-/// Construct a IRMapping from `linalgOp` to `genericLinalgModelOp`.
-/// Walk both ops and check whether all subops are the same.
-static LogicalResult
-haveIdenticalBodiesImpl(linalg::LinalgOp linalgOp,
- linalg::LinalgOp genericLinalgModelOp) {
- IRMapping bvm;
- bvm.map(linalgOp.getBlock()->getArguments(),
- genericLinalgModelOp.getBlock()->getArguments());
- SmallVector<Operation *> linalgBodyOps;
- linalgOp.getBlock()->walk(
- [&](Operation *op) { linalgBodyOps.push_back(op); });
-
- unsigned idx = 0;
- WalkResult res = genericLinalgModelOp.getBlock()->walk([&](Operation *op) {
- Operation *linalgSubOp = linalgBodyOps[idx++];
- if (op->getName() != linalgSubOp->getName()) {
- return WalkResult::interrupt();
- }
- if (op->getAttrs() != linalgSubOp->getAttrs()) {
- return WalkResult::interrupt();
- }
- for (auto it : llvm::zip(op->getOperands(), linalgSubOp->getOperands())) {
- if (std::get<0>(it) != bvm.lookupOrNull(std::get<1>(it))) {
- return WalkResult::interrupt();
- }
- }
- bvm.map(linalgSubOp->getResults(), op->getResults());
- return WalkResult::advance();
- });
-
- return success(!res.wasInterrupted());
-}
-
-/// Dispatch body equivalence check depending on case.
-static LogicalResult haveEquivalentBodies(linalg::LinalgOp linalgOp,
- linalg::LinalgOp genericLinalgModelOp,
- PatternRewriter &rewriter) {
- if (succeeded(haveIdenticalBodiesImpl(linalgOp, genericLinalgModelOp))) {
- return success();
- }
- // TODO: haveEquivalentBodiesImpl, see e.g.
- // https://gist.github.com/nicolasvasilache/39e89e18c46e02335c16db6ec20a07e3
- return failure();
-}
-
-/// Succeed when `linalgOp` and `linalgModelOp` are deemed equivalent.
-static LogicalResult isEquivalentToOpImpl(PatternRewriter &rewriter,
- linalg::LinalgOp linalgOp,
- linalg::LinalgOp linalgModelOp) {
- // If basic properties do not match, return failure.
- {
- SmallVector<Value> opInputs = linalgOp.getDpsInputs();
- SmallVector<Value> modelInputs = linalgModelOp.getDpsInputs();
- ValueRange opOutputs = linalgOp.getDpsInits();
- ValueRange modelOutputs = linalgModelOp.getDpsInits();
- auto notEqualFn = [](std::tuple<Value, Value> in) -> bool {
- return std::get<0>(in) != std::get<1>(in);
- };
-
- if (opInputs.size() != modelInputs.size() ||
- opOutputs.size() != modelOutputs.size() ||
- llvm::any_of(llvm::zip(opInputs, modelInputs), notEqualFn) ||
- llvm::any_of(llvm::zip(opOutputs, modelOutputs), notEqualFn) ||
- linalgOp.getIndexingMaps() != linalgModelOp.getIndexingMaps() ||
- linalgOp.getIteratorTypesArray() !=
- linalgModelOp.getIteratorTypesArray()) {
- return failure();
- }
- }
-
- // Build the block and go perform a body comparison.
- {
- // createBlock moves the insertion point, scope it in an RAII block.
- OpBuilder::InsertionGuard guard(rewriter);
- Region &r = linalgModelOp->getRegion(0);
- Block *bodyBlock = rewriter.createBlock(
- &r, r.end(), linalgOp.getBlock()->getArgumentTypes(),
- llvm::map_to_vector<4>(linalgOp.getBlock()->getArguments(),
- [](Value v) { return v.getLoc(); }));
- ImplicitLocOpBuilder b(linalgModelOp.getLoc(), rewriter);
- auto regionBuilder = linalgModelOp.getRegionBuilder();
- llvm::ArrayRef<mlir::NamedAttribute> attrs = {};
- regionBuilder(b, *bodyBlock, attrs, /*emitError=*/{});
- }
-
- return haveEquivalentBodies(linalgOp, linalgModelOp, rewriter);
-}
-
-/// Check whether the unique Operation* stored in `pdlValues[0]` (assumed) is
-/// equivalent to the unique StringRefAttr passed in `pdlValues[1]` (assumed).
-/// Equivalence is achieved when either:
-/// 1. `pdlValues[0]` has the name stored in `pdlValues[1]`.
-/// 2. `pdlValues[0]` and `pdlValues[1]` are both linalg ops and their
-/// structured interfaces as well as their bodies are equivalent.
-/// Structured interfaces equivalence is a simple attribute level check.
-/// Body equivalence is more involved and currently limited:
-/// a. the current impl constructs an instance of the op whose name is
-/// specified in `pdlValues[1]` and checks for exact body equality.
-/// b. a more advanced version would "subtract" the bodies and fold, cse
-/// and canonicalize to fixed point. If the result is "all zeros",
-/// then the bodies would be equivalent (really isomorphic).
-/// 3. other cases TBD (e.g. vector.generic when available).
-static LogicalResult isEquivalentToOp(PatternRewriter &rewriter,
- PDLResultList &pdlResults,
- ArrayRef<PDLValue> pdlValues) {
- assert(pdlValues.size() == 2 && "expected 2 PDL values");
- Operation *operation = pdlValues[0].cast<Operation *>();
- Attribute attribute = pdlValues[1].cast<Attribute>();
-
- auto modelOpNameAttr = dyn_cast<StringAttr>(attribute);
- if (!modelOpNameAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- auto modelOpName = modelOpNameAttr.strref();
-
- // 1. If op has name `modelOpName`, the match is trivial.
- if (operation->getName().getStringRef() == modelOpName) {
- return success();
- }
-
- // 2. Linalg vs Linalg.
- // Create op from `modelOpName`.
- OperationState modelOpState(
- operation->getLoc(), modelOpName, operation->getOperands(),
- operation->getResultTypes(), operation->getAttrs());
- modelOpState.addRegion();
- Operation *modelOp = rewriter.create(modelOpState);
- auto g1 = llvm::scope_exit([&]() { rewriter.eraseOp(modelOp); });
- linalg::LinalgOp linalgOp = dyn_cast<linalg::LinalgOp>(operation);
- linalg::LinalgOp linalgModelOp = dyn_cast<linalg::LinalgOp>(modelOp);
- if (linalgOp && linalgModelOp) {
- return isEquivalentToOpImpl(rewriter, linalgOp, linalgModelOp);
- }
-
- // 3. TBD
- return failure();
-}
-
-/// Assume that:
-/// 1. `pdlValues[0]` is an operands range
-/// 2. `pdlValues[1]` contains a DictAttr with `operand_number`, `dim` and
-/// `divisor` IntegerAttr entries.
-/// Succeed if `operands`[`operand_number`] is a ranked type whose `dim` is a
-/// multiple of `divisor`.
-/// Note: 0 is the convention to express "do not tile", it is considered to
-/// divide everything.
-static LogicalResult isDimMultipleOf(PatternRewriter &rewriter,
- PDLResultList &pdlResults,
- ArrayRef<PDLValue> pdlValues) {
- assert(pdlValues.size() == 2 && "expected 2 PDL values");
- ValueRange operands = pdlValues[0].cast<ValueRange>();
- Attribute attribute = pdlValues[1].cast<Attribute>();
-
- auto dict = dyn_cast<DictionaryAttr>(attribute);
- if (!dict) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
-
- int64_t dim;
- auto dimAttr = dict.getAs<IntegerAttr>("dim");
- if (!dimAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- dim = dimAttr.getInt();
-
- int64_t divisor;
- auto divisorAttr = dict.getAs<IntegerAttr>("divisor");
- if (!divisorAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- divisor = divisorAttr.getInt();
-
- int64_t operandNumber;
- auto operandNumberAttr = dict.getAs<IntegerAttr>("operand_number");
- if (!operandNumberAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- operandNumber = operandNumberAttr.getInt();
-
- ShapedType shapedType;
- if (static_cast<int64_t>(operands.size()) > operandNumber) {
- shapedType = dyn_cast<ShapedType>(operands[operandNumber].getType());
- }
- if (!shapedType || shapedType.getRank() <= dim) {
- return failure();
- }
- return success(divisor == 0 || (shapedType.getShape()[dim] > 0 &&
- shapedType.getShape()[dim] % divisor == 0));
-}
-
-/// Assume that:
-/// 1. `pdlValues[0]` is an operands range
-/// 2. `pdlValues[1]` contains a DictAttr with `operand_number` and `dim`
-/// IntegerAttr entries.
-/// Succeed if `value`[`operand_number`] is a ranked type whose `dim` is
-/// dynamic.
-static LogicalResult isDimStatic(PatternRewriter &rewriter,
- PDLResultList &pdlResults,
- ArrayRef<PDLValue> pdlValues) {
- assert(pdlValues.size() == 2 && "expected 2 PDL values");
- ValueRange operands = pdlValues[0].cast<ValueRange>();
- Attribute attribute = pdlValues[1].cast<Attribute>();
-
- auto dict = dyn_cast<DictionaryAttr>(attribute);
- if (!dict) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
-
- int64_t dim;
- auto dimAttr = dict.getAs<IntegerAttr>("dim");
- if (!dimAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- dim = dimAttr.getInt();
-
- int64_t operandNumber;
- auto operandNumberAttr = dict.getAs<IntegerAttr>("operand_number");
- if (!operandNumberAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- operandNumber = operandNumberAttr.getInt();
-
- ShapedType shapedType;
- if (static_cast<int64_t>(operands.size()) > operandNumber) {
- shapedType = dyn_cast<ShapedType>(operands[operandNumber].getType());
- }
- return success(shapedType && !shapedType.isDynamicDim(dim));
-}
-
-/// Assume that:
-/// 1. `pdlValues[0]` is an operands range
-/// 2. `pdlValues[1]` contains a DictAttr with `operand_number` and `dim`
-/// IntegerAttr entries.
-/// Succeed if `value`[`operand_number`] is a ranked type whose `dim` is
-/// dynamic.
-static LogicalResult isDimDynamic(PatternRewriter &rewriter,
- PDLResultList &pdlResults,
- ArrayRef<PDLValue> pdlValues) {
- assert(pdlValues.size() == 2 && "expected 2 PDL values");
- ValueRange operands = pdlValues[0].cast<ValueRange>();
- Attribute attribute = pdlValues[1].cast<Attribute>();
-
- auto dict = dyn_cast<DictionaryAttr>(attribute);
- if (!dict) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
-
- int64_t dim;
- auto dimAttr = dict.getAs<IntegerAttr>("dim");
- if (!dimAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- dim = dimAttr.getInt();
-
- int64_t operandNumber;
- auto operandNumberAttr = dict.getAs<IntegerAttr>("operand_number");
- if (!operandNumberAttr) {
- return failure(); // TODO: notifyMatchFailure needs an Operation* handle.
- }
- operandNumber = operandNumberAttr.getInt();
-
- ShapedType shapedType;
- if (static_cast<int64_t>(operands.size()) > operandNumber) {
- shapedType = dyn_cast<ShapedType>(operands[operandNumber].getType());
- }
- return success(shapedType && shapedType.isDynamicDim(dim));
-}
-
-//===----------------------------------------------------------------------===//
-// StructuredTransformOpsExtension
-//===----------------------------------------------------------------------===//
-
-mlir::transform_ext::StructuredTransformOpsExtension::
- StructuredTransformOpsExtension() {
- registerTransformOps<
-#define GET_OP_LIST
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.cpp.inc"
- >();
-
- addDialectDataInitializer<transform::PDLMatchHooks>(
- [&](transform::PDLMatchHooks &hooks) {
- llvm::StringMap<PDLConstraintFunction> constraints;
- constraints.try_emplace("nestedInFunc", nestedInFunc);
- constraints.try_emplace("isDimDynamic", isDimDynamic);
- constraints.try_emplace("isDimMultipleOf", isDimMultipleOf);
- constraints.try_emplace("isDimStatic", isDimStatic);
- constraints.try_emplace("isEquivalentToOp", isEquivalentToOp);
- hooks.mergeInPDLMatchHooks(std::move(constraints));
- });
-
- declareDependentDialect<bufferization::BufferizationDialect>();
- declareDependentDialect<vector::VectorDialect>();
-}
-
-#define GET_OP_CLASSES
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.cpp.inc"
-
-//===----------------------------------------------------------------------===//
-// ErrorCheckingTrackingListener
-//===----------------------------------------------------------------------===//
-
-void ErrorCheckingTrackingListener::notifyPayloadReplacementNotFound(
- Operation *op, ValueRange values, DiagnosedSilenceableFailure &&diag) {
- // Certain ops can dropped safely.
- if (isa<scf::ForOp>(op)) {
- LLVM_DEBUG(DBGS() << "Silently dropping scf.for op mapping\n");
- return;
- }
-
- SmallVector<Diagnostic> diags;
- diag.takeDiagnostics(diags);
- if (!status.succeeded()) {
- status.takeDiagnostics(diags);
- }
- status = DiagnosedSilenceableFailure::silenceableFailure(std::move(diags));
-
- status = emitSilenceableFailure(
- getTransformOp(), "!!! tracking listener failed to find replacement op");
- status.attachNote(op->getLoc()) << "replaced op";
- for (Value v : values) {
- status.attachNote(v.getLoc()) << "replacement value";
- }
-}
-
-//===---------------------------------------------------------------------===//
-// MatchCallbackOp
-//===---------------------------------------------------------------------===//
-
-DiagnosedSilenceableFailure transform_ext::MatchCallbackOp::apply(
- mlir::transform::TransformRewriter &rewriter,
- mlir::transform::TransformResults &results,
- mlir::transform::TransformState &state) {
- auto setEmptyResults = [&results, this] {
- for (OpResult value : getResults()) {
- results.set(value, {});
- }
- };
- auto errorOut = [this, &setEmptyResults] {
- setEmptyResults();
- return emitSilenceableError();
- };
-
- auto *registry = state.getExtension<transform_ext::MatchCallbacksRegistry>();
- if (!registry) {
- return errorOut() << "match registry not available";
- }
-
- const transform_ext::MatchCallbacksRegistry::MatchCallbackFn *callback =
- registry->get(getCallbackName());
- if (!callback) {
- return errorOut() << "callback '" << getCallbackName()
- << "' not found in the registry";
- }
-
- MatchCallbackResult result;
- DiagnosedSilenceableFailure status =
- (*callback)(result, getLoc(), state, getInputs());
- if (!status.succeeded()) {
- setEmptyResults();
- if (status.isDefiniteFailure()) {
- return status;
- }
- if (getFailurePropagationMode() ==
- mlir::transform::FailurePropagationMode::Propagate) {
- return emitSilenceableError() << "failed to match";
- } else {
- return DiagnosedSilenceableFailure::success();
- }
- }
- if (getNumResults() != result.getNumPayloadGroups()) {
- return errorOut()
- << "callback produced a different number of handles than expected ( "
- << result.getNumPayloadGroups() << " vs " << getNumResults() << " )";
- }
-
- for (OpResult value : getResults()) {
- results.set(value, result.getPayloadGroup(value.getResultNumber()));
- }
- return DiagnosedSilenceableFailure::success();
-}
-
-void transform_ext::MatchCallbackOp::getEffects(
- SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
- mlir::transform::onlyReadsHandle(getInputsMutable(), effects);
- mlir::transform::producesHandle(getOutputs(), effects);
- // TODO: it doesn't really modify the payload, we need a separate resource for
- // this mapping.
- mlir::transform::modifiesPayload(effects);
-}
-
-//===---------------------------------------------------------------------===//
-// Callbacks for tests driven by RegisterMatchCallbacksOp
-//===---------------------------------------------------------------------===//
-
-/// Match callback for "_test_match_callback" hook. Matches any payload
-/// operations associated with operand handles unless they have the
-/// "test.iree_transform_do_not_match" attribute, in which case produces a
-/// silenceable failure.
-static DiagnosedSilenceableFailure
-testMatchCallbackCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- bool hadFailures = false;
- for (Value handle : handles) {
- if (llvm::any_of(state.getPayloadOps(handle), [](Operation *op) {
- return op->hasAttr("test.iree_transform_do_not_match");
- })) {
- res.addPayloadGroup(ArrayRef<Operation *>());
- hadFailures = true;
- } else {
- res.addPayloadGroup(state.getPayloadOps(handle));
- }
- }
- if (hadFailures) {
- return emitSilenceableFailure(loc) << "failed to match";
- }
- return DiagnosedSilenceableFailure::success();
-}
-
-static DiagnosedSilenceableFailure testRepeatedMatcherUseCallback(
- transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state, ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- transform_ext::MatcherContext matcherContext;
- auto &operand = transform_ext::m_StructuredOp(matcherContext);
- auto &first = transform_ext::m_StructuredOp(matcherContext).input(0, operand);
- auto &second = transform_ext::m_StructuredOp(matcherContext)
- .input(0, operand)
- .input(1, first);
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- second.resetCapture();
- if (!matchPattern(op, second)) {
- return WalkResult::advance();
- }
-
- res.addPayloadGroup({first.getCaptured()});
- res.addPayloadGroup({second.getCaptured()});
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-static DiagnosedSilenceableFailure
-testValueMatcherCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- transform_ext::MatcherContext matcherContext;
- auto &operand = transform_ext::m_Value(matcherContext);
- auto &first = transform_ext::m_StructuredOp(matcherContext).input(0, operand);
- auto &second = transform_ext::m_StructuredOp(matcherContext)
- .input(0, operand)
- .input(1, first);
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- second.resetCapture();
- if (!matchPattern(op, second)) {
- return WalkResult::advance();
- }
-
- res.addPayloadGroup({first.getCaptured()});
- res.addPayloadGroup({second.getCaptured()});
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-static DiagnosedSilenceableFailure testShapedValueMatcherCallback(
- transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state, ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- int64_t rank;
- SmallVector<int64_t> dims;
- transform_ext::MatcherContext matcherContext;
- auto &value = transform_ext::m_ShapedValue(matcherContext);
- value.rank(transform_ext::CaptureRank(rank))
- .dim(transform_ext::AllDims(), transform_ext::CaptureDims(dims));
- auto &opMatcher =
- transform_ext::m_Operation<linalg::GenericOp>(matcherContext);
- opMatcher.result(0, value);
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- opMatcher.resetCapture();
- if (!matchPattern(op, opMatcher)) {
- return WalkResult::advance();
- }
-
- op->emitRemark() << "rank: " << rank;
- std::string message;
- llvm::raw_string_ostream os(message);
- llvm::interleaveComma(dims, os);
- os.flush();
- op->emitRemark() << "dimensions: " << message;
-
- res.addPayloadGroup({opMatcher.getCaptured()});
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-//===---------------------------------------------------------------------===//
-// Callbacks for codegen driven by RegisterMatchCallbacksOp.
-//===---------------------------------------------------------------------===//
-
-/// Match callback for a convolution with optional fill and trailing
-/// elementwise operations. Matches *the first* occurrence of such a convolution
-/// within an op associated with the given handle.
-///
-/// Input handles:
-///
-/// - container op, must be associated with one operation.
-///
-/// Output handles:
-///
-/// - the "fill" op preceding the convolution, if present;
-/// - convolution op;
-/// - trailing elementwise op, if any.
-static DiagnosedSilenceableFailure
-convolutionCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
-
- transform_ext::StructuredOpMatcher *pattern, *fill, *trailing;
- transform_ext::MatchedConvolutionCaptures ignore;
- transform_ext::MatcherContext matcherContext;
- makeConvolutionMatcher(matcherContext, pattern, fill, trailing, ignore,
- /*mustMatchEntireFunc=*/true);
-
- // TODO: need a mechanism for this to go around the entire IR,
- // potentially with list matches for each group.
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- pattern->resetCapture();
- if (!matchPattern(op, *pattern)) {
- return WalkResult::advance();
- }
-
- // TODO: notify properly.
- LLVM_DEBUG({
- DBGS() << "fill:\n";
- if (fill->getCaptured()) {
- DBGS() << fill->getCaptured() << "\n";
- }
- DBGS() << "pattern: " << pattern->getCaptured() << "\n";
- DBGS() << "trailing:\n";
- if (trailing->getCaptured()) {
- DBGS() << trailing->getCaptured() << "\n";
- }
- });
-
- res.addPotentiallyEmptyPayloadGroup(fill->getCaptured());
- res.addPayloadGroup({pattern->getCaptured()});
- res.addPotentiallyEmptyPayloadGroup(trailing->getCaptured());
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-/// Match callback for a reduction with optional leading and trailing
-/// elementwise operations. Matches *the first* occurrence of such a reduction
-/// within an op associated with the given handle.
-///
-/// Input handles:
-///
-/// - container op, must be associated with one operation.
-///
-/// Output handles:
-///
-/// - leading elementwise op, if any;
-/// - the "fill" op preceding the reduction;
-/// - reduction op;
-/// - trailing elementwise op, if any.
-static DiagnosedSilenceableFailure
-reductionCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles, bool mustMatchEntireFunc) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
-
- transform_ext::StructuredOpMatcher *pattern, *fill, *leading, *trailing;
- transform_ext::MatchedReductionCaptures ignore;
- transform_ext::MatcherContext matcherContext;
- makeReductionMatcher(matcherContext, pattern, fill, leading, trailing, ignore,
- mustMatchEntireFunc);
-
- // TODO: need a mechanism for this to go around the entire IR,
- // potentially with list matches for each group.
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- pattern->resetCapture();
- if (!matchPattern(op, *pattern)) {
- return WalkResult::advance();
- }
-
- // TODO: notify properly.
- LLVM_DEBUG({
- DBGS() << "leading:\n";
- if (leading->getCaptured()) {
- DBGS() << leading->getCaptured() << "\n";
- }
- DBGS() << "fill: " << fill->getCaptured() << "\n";
- DBGS() << "pattern: " << pattern->getCaptured() << "\n";
- DBGS() << "trailing:\n";
- if (trailing->getCaptured()) {
- DBGS() << trailing->getCaptured() << "\n";
- }
- });
-
- res.addPotentiallyEmptyPayloadGroup(leading->getCaptured());
- res.addPayloadGroup({fill->getCaptured()});
- res.addPayloadGroup({pattern->getCaptured()});
- res.addPotentiallyEmptyPayloadGroup(trailing->getCaptured());
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-/// Match callback for a matmul with fill and optional trailing
-/// elementwise operations. Matches *the first* occurrence of such a convolution
-/// within an op associated with the given handle.
-///
-/// Input handles:
-///
-/// - container op, must be associated with one operation.
-///
-/// Output handles:
-///
-/// - the "fill" op preceding the convolution, if present;
-/// - convolution op;
-/// - trailing elementwise op, if any.
-static DiagnosedSilenceableFailure
-matmulCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
-
- transform_ext::StructuredOpMatcher *pattern, *fill, *trailing;
- transform_ext::MatchedMatmulCaptures ignore;
- transform_ext::MatcherContext matcherContext;
- makeMatmulMatcher(matcherContext, pattern, fill, trailing, ignore,
- /*mustMatchEntireFunc=*/true);
-
- // TODO: need a mechanism for this to go around the entire IR,
- // potentially with list matches for each group.
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- pattern->resetCapture();
- if (!matchPattern(op, *pattern)) {
- return WalkResult::advance();
- }
-
- // TODO: notify properly.
- LLVM_DEBUG({
- DBGS() << "fill:\n";
- if (fill->getCaptured()) {
- DBGS() << fill->getCaptured() << "\n";
- }
- DBGS() << "pattern: " << pattern->getCaptured() << "\n";
- DBGS() << "trailing:\n";
- if (trailing->getCaptured()) {
- DBGS() << trailing->getCaptured() << "\n";
- }
- });
-
- res.addPayloadGroup({fill->getCaptured()});
- res.addPayloadGroup({pattern->getCaptured()});
- res.addPotentiallyEmptyPayloadGroup(trailing->getCaptured());
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-/// Match callback for linalg.batch_matmul and its linalg.generic equivalent fed
-/// by a linalg.fill.
-///
-/// Input handles:
-///
-/// - the container op, must be associated with one operation.
-///
-/// Output handles:
-///
-/// - the fill op initializing the output;
-/// - the main compute op.
-static DiagnosedSilenceableFailure
-batchMatmulCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state,
- ValueRange handles) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
-
- transform_ext::StructuredOpMatcher *pattern, *fill;
- transform_ext::MatchedMatmulCaptures ignore;
- transform_ext::MatcherContext matcherContext;
- transform_ext::makeBatchMatmulMatcher(matcherContext, pattern, fill, ignore,
- /*mustMatchEntireFunc*/ true);
-
- // TODO: need a mechanism for this to go around the entire IR,
- // potentially with list matches for each group.
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- pattern->resetCapture();
- if (!matchPattern(op, *pattern)) {
- return WalkResult::advance();
- }
-
- // TODO: notify properly
- LLVM_DEBUG({
- DBGS() << "fill:" << fill->getCaptured() << "\n";
- DBGS() << "pattern: " << pattern->getCaptured() << "\n";
- });
-
- res.addPayloadGroup({fill->getCaptured()});
- res.addPayloadGroup({pattern->getCaptured()});
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match batch matmul";
-}
-
-/// Match callback for a tensor.pad. Matches *the first* occurrence of such pad
-/// within an op associated with the given handle.
-///
-/// Input handles:
-///
-/// - the container op, must be associated with one operation.
-///
-/// Output handles:
-///
-/// - the pad op.
-static DiagnosedSilenceableFailure
-padCallback(transform_ext::MatchCallbackResult &res, Location loc,
- const mlir::transform::TransformState &state, ValueRange handles,
- bool mustMatchEntireFunc) {
- if (handles.size() != 1 ||
- !llvm::hasSingleElement(state.getPayloadOps(handles[0]))) {
- return emitSilenceableFailure(loc)
- << "expected one handle to one operation";
- }
-
- transform_ext::CapturingOpMatcher *pattern;
- transform_ext::MatchedPadCaptures ignore;
- transform_ext::MatcherContext matcherContext;
- makePadMatcher(matcherContext, pattern, ignore, mustMatchEntireFunc);
-
- Operation *root = *state.getPayloadOps(handles[0]).begin();
-
- WalkResult walkResult = root->walk([&](Operation *op) {
- pattern->resetCapture();
- if (!matchPattern(op, *pattern)) {
- return WalkResult::advance();
- }
-
- // TODO: notify properly.
- LLVM_DEBUG({
- DBGS() << "pad:\n";
- if (pattern->getCaptured()) {
- DBGS() << pattern->getCaptured() << "\n";
- }
- });
-
- res.addPayloadGroup({pattern->getCaptured()});
- return WalkResult::interrupt();
- });
-
- if (walkResult.wasInterrupted()) {
- return DiagnosedSilenceableFailure::success();
- }
- return emitSilenceableFailure(loc) << "failed to match";
-}
-
-//===---------------------------------------------------------------------===//
-// RegisterMatchCallbacksOp
-//===---------------------------------------------------------------------===//
-
-DiagnosedSilenceableFailure transform_ext::RegisterMatchCallbacksOp::apply(
- mlir::transform::TransformRewriter &rewriter,
- mlir::transform::TransformResults &results,
- mlir::transform::TransformState &state) {
- auto ®istry = state.addExtension<transform_ext::MatchCallbacksRegistry>();
- registry.registerCallback("_test_match_callback", testMatchCallbackCallback);
- registry.registerCallback("_test_repeated_matcher_use_callback",
- testRepeatedMatcherUseCallback);
- registry.registerCallback("_test_value_matcher_callback",
- testValueMatcherCallback);
- registry.registerCallback("_test_shaped_value_matcher_callback",
- testShapedValueMatcherCallback);
- registry.registerCallback("convolution", convolutionCallback);
- registry.registerCallback("matmul", matmulCallback);
- registry.registerCallback("batch_matmul", batchMatmulCallback);
- registry.registerCallback("pad", wrapAsEntireFuncMatch(padCallback));
- registry.registerCallback("reduction",
- wrapAsEntireFuncMatch(reductionCallback));
- registry.registerCallback("reduction_partial",
- wrapAsPartialMatch(reductionCallback));
- return DiagnosedSilenceableFailure::success();
-}
-
-void transform_ext::RegisterMatchCallbacksOp::getEffects(
- SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
- // TODO: it doesn't really modify the payload, we need a separate resource for
- // this mapping.
- mlir::transform::modifiesPayload(effects);
-}
-
-//===---------------------------------------------------------------------===//
-// TakeFirstOp
-//===---------------------------------------------------------------------===//
-
-DiagnosedSilenceableFailure
-transform_ext::TakeFirstOp::apply(mlir::transform::TransformRewriter &rewriter,
- mlir::transform::TransformResults &results,
- mlir::transform::TransformState &state) {
- SmallVector<Operation *> concatenated;
- bool found = false;
- for (Value handle : getInputs()) {
- auto payloads = state.getPayloadOps(handle);
- if (payloads.empty()) {
- continue;
- }
- if (!found) {
- results.set(cast<OpResult>(getFirst()), payloads);
- found = true;
- } else {
- llvm::append_range(concatenated, payloads);
- }
- }
-
- if (!found) {
- results.set(cast<OpResult>(getFirst()), {});
- }
- results.set(cast<OpResult>(getRest()), concatenated);
- return DiagnosedSilenceableFailure::success();
-}
-
-void transform_ext::TakeFirstOp::getEffects(
- SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
- mlir::transform::onlyReadsHandle(getInputsMutable(), effects);
- mlir::transform::producesHandle(getOperation()->getOpResults(), effects);
-}
-
-//===---------------------------------------------------------------------===//
-// EmitRemarkOp
-//===---------------------------------------------------------------------===//
-
-DiagnosedSilenceableFailure transform_ext::EmitRemarkOp::applyToOne(
- transform::TransformRewriter &rewriter, Operation *target,
- mlir::transform::ApplyToEachResultList &results,
- mlir::transform::TransformState &state) {
- for (Operation *payload : state.getPayloadOps(getHandle())) {
- payload->emitRemark(getMessage());
- }
- return DiagnosedSilenceableFailure::success();
-}
-
-void transform_ext::EmitRemarkOp::getEffects(
- SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
- mlir::transform::onlyReadsHandle(getHandleMutable(), effects);
- mlir::transform::onlyReadsPayload(effects);
-}
diff --git a/llvm-external-projects/iree-dialects/lib/Transforms/CMakeLists.txt b/llvm-external-projects/iree-dialects/lib/Transforms/CMakeLists.txt
deleted file mode 100644
index da2cbd9..0000000
--- a/llvm-external-projects/iree-dialects/lib/Transforms/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-
-add_mlir_library(IREEDialectsTransforms
- TransformMatchers.cpp
-
- LINK_LIBS PRIVATE
- # TODO: break dialect dependency by implementing the transformation separately
- # and registering it.
- MLIRArithDialect
- MLIRAsyncDialect
- MLIRFuncDialect
- MLIRLinalgDialect
- MLIRLinalgTransforms
- MLIRMathDialect
-
- DEPENDS
- mlir-headers
-)
-
-iree_dialects_target_includes(IREEDialectsTransforms)
diff --git a/llvm-external-projects/iree-dialects/lib/Transforms/TransformMatchers.cpp b/llvm-external-projects/iree-dialects/lib/Transforms/TransformMatchers.cpp
deleted file mode 100644
index a90ff9b..0000000
--- a/llvm-external-projects/iree-dialects/lib/Transforms/TransformMatchers.cpp
+++ /dev/null
@@ -1,1845 +0,0 @@
-// Copyright 2022 The IREE Authors
-//
-// Licensed 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
-
-#include "iree-dialects/Transforms/TransformMatchers.h"
-
-#include "mlir/Analysis/SliceAnalysis.h"
-#include "mlir/Dialect/Arith/IR/Arith.h"
-#include "mlir/Dialect/Linalg/IR/Linalg.h"
-#include "mlir/Dialect/Math/IR/Math.h"
-#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Interfaces/FunctionInterfaces.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/Support/Debug.h"
-
-using namespace mlir;
-
-#define DEBUG_TYPE "transform-matchers"
-#define DBGS() llvm::dbgs() << "[" DEBUG_TYPE "] "
-#define DBGSNL() llvm::dbgs() << "\n[" DEBUG_TYPE "] "
-
-//===---------------------------------------------------------------------===//
-// CapturingMatcherBase
-//===---------------------------------------------------------------------===//
-
-void transform_ext::CapturingMatcherBase::getAllNested(
- SmallVectorImpl<CapturingOpMatcher *> &nested) {
-
- SetVector<CapturingOpMatcher *> found;
- found.insert(nested.begin(), nested.end());
- int64_t start = found.size();
-
- auto appendOne = [&found](CapturingMatcherBase &one) {
- found.insert(one.nestedCapturingMatchers.begin(),
- one.nestedCapturingMatchers.end());
- for (CapturingValueMatcher *valueMatcher :
- one.nestedCapturingValueMatchers) {
- found.insert(valueMatcher->nestedCapturingMatchers.begin(),
- valueMatcher->nestedCapturingMatchers.end());
- }
- };
-
- appendOne(*this);
- for (int64_t position = start; position < found.size(); ++position) {
- appendOne(*found[position]);
- }
-
- llvm::append_range(nested, found.getArrayRef());
-}
-
-void transform_ext::CapturingMatcherBase::getAllNestedValueMatchers(
- SmallVectorImpl<CapturingValueMatcher *> &nested) {
-
- SetVector<CapturingValueMatcher *> found;
- found.insert(nested.begin(), nested.end());
- int64_t start = found.size();
-
- auto appendOne = [&found](CapturingMatcherBase &one) {
- found.insert(one.nestedCapturingValueMatchers.begin(),
- one.nestedCapturingValueMatchers.end());
- for (CapturingOpMatcher *opMatcher : one.nestedCapturingMatchers) {
- found.insert(opMatcher->nestedCapturingValueMatchers.begin(),
- opMatcher->nestedCapturingValueMatchers.end());
- }
- };
-
- appendOne(*this);
- for (int64_t position = start; position < found.size(); ++position) {
- appendOne(*found[position]);
- }
-
- llvm::append_range(nested, found.getArrayRef());
-}
-
-void transform_ext::CapturingMatcherBase::resetCapture() {
- SmallVector<CapturingOpMatcher *> nested;
- getAllNested(nested);
- for (CapturingOpMatcher *matcher : nested) {
- matcher->captured = nullptr;
- }
- SmallVector<CapturingValueMatcher *> nestedValue;
- getAllNestedValueMatchers(nestedValue);
- for (CapturingValueMatcher *matcher : nestedValue) {
- matcher->captured = nullptr;
- }
-}
-
-//===---------------------------------------------------------------------===//
-// CapturingOpMatcher
-//===---------------------------------------------------------------------===//
-
-bool transform_ext::CapturingOpMatcher::checkAllTilableMatched(
- Operation *parent, Operation *op,
- ArrayRef<transform_ext::CapturingOpMatcher *> matchers) {
- LLVM_DEBUG(DBGS() << "all tilable ops captured");
- int64_t numTilableOps = 0;
- if (!parent) {
- return false;
- }
- parent->walk([&](TilingInterface Op) { ++numTilableOps; });
-
- llvm::SmallPtrSet<Operation *, 6> matched;
- for (CapturingOpMatcher *nested : matchers) {
- if (Operation *captured = nested->getCaptured()) {
- matched.insert(captured);
- }
- }
-
- // Don't forget to include the root matcher.
- matched.insert(op);
- return numTilableOps == matched.size();
-}
-
-bool transform_ext::CapturingOpMatcher::match(Operation *op) {
- auto debugRAII = llvm::scope_exit([] { LLVM_DEBUG(DBGS() << "-------\n"); });
- LLVM_DEBUG(DBGS() << "matching: " << *op << "\n");
-
- if (getCaptured()) {
- LLVM_DEBUG(DBGS() << "found an already captured op: ");
- if (getCaptured() == op) {
- LLVM_DEBUG(llvm::dbgs() << "same\n");
- return true;
- } else {
- LLVM_DEBUG(llvm::dbgs() << "different\n");
- return false;
- }
- }
-
- if (!llvm::all_of(predicates, [op](const PredicateFn &fn) {
- bool result = fn(op);
- LLVM_DEBUG(llvm::dbgs() << ": " << result << "\n");
- return result;
- })) {
- return false;
- }
-
- captured = op;
- return true;
-}
-
-void transform_ext::CapturingOpMatcher::debugOutputForCreate(
- ArrayRef<StringRef> opNames) {
- LLVM_DEBUG(DBGS() << "operation type is one of {";
- llvm::interleaveComma(opNames, llvm::dbgs()); llvm::dbgs() << "}");
-}
-
-/// Apply the given matcher to the given object, produce debug messages.
-template <typename Matcher, typename Object = typename llvm::function_traits<
- typename Matcher::match>::template args<0>>
-static bool recursiveMatch(Matcher &matcher, Object &object,
- StringRef extraMessage = "") {
- LLVM_DEBUG(llvm::dbgs() << "\n[" DEBUG_TYPE "] " << "start recursive match ("
- << extraMessage << ") {\n");
- bool result = matcher.match(object);
- LLVM_DEBUG(DBGS() << "} end recursive match");
- return result;
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::alternatives(
- transform_ext::CapturingOpMatcher &first,
- transform_ext::CapturingOpMatcher &second) {
- addPredicate([&first, &second](Operation *op) {
- LLVM_DEBUG(DBGS() << "matching alternatives\n");
- return recursiveMatch(first, op, "alternative 1") ||
- recursiveMatch(second, op, "alternative 2");
- });
- return *this;
-}
-
-//---------------------------------------------------------------------------//
-// Predicates for operands and results.
-//---------------------------------------------------------------------------//
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::operand(transform_ext::NumEqualsTo num) {
- addPredicate([=](Operation *op) {
- LLVM_DEBUG(DBGS() << "operation has exactly " << num.value << " operands");
- return num.value == op->getNumOperands();
- });
- return *this;
-}
-
-/// If `pos` is negative, returns the number of the operand in op starting from
-/// the last. For example, -1 means the last operand, -2 means the
-/// second-to-last, etc. Returns nullopt if pos is out-of-bounds, both positive
-/// and negative.
-static std::optional<int64_t> remapNegativeOperandNumber(int64_t pos,
- Operation *op) {
- int64_t updated = pos < 0 ? op->getNumOperands() + pos : pos;
- if (updated < 0 || updated >= op->getNumOperands()) {
- LLVM_DEBUG(DBGS() << "match operand #" << pos
- << "that does not exist in the operation");
- return std::nullopt;
- }
- return updated;
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::operand(int64_t pos,
- CapturingOpMatcher &nested) {
- addPredicate([pos, &nested](Operation *op) {
- std::optional<int64_t> operandNo = remapNegativeOperandNumber(pos, op);
- if (!operandNo) {
- return false;
- }
- LLVM_DEBUG(DBGS() << "operand #" << pos << " is defined by an operation");
- Operation *definingOp = op->getOperand(*operandNo).getDefiningOp();
- if (!definingOp) {
- return false;
- }
- return recursiveMatch(nested, definingOp);
- });
- recordNestedMatcher(nested);
- return *this;
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::operand(int64_t pos,
- CapturingValueMatcher &nested) {
- addPredicate([pos, &nested](Operation *op) {
- std::optional<int64_t> operandNo = remapNegativeOperandNumber(pos, op);
- if (!operandNo) {
- return false;
- }
- LLVM_DEBUG(DBGS() << "operand #" << pos << " is");
- Value operand = op->getOperand(*operandNo);
- return recursiveMatch(nested, operand);
- });
- recordNestedMatcher(nested);
- return *this;
-}
-
-transform_ext::CapturingOpMatcher &transform_ext::CapturingOpMatcher::operand(
- int64_t position, std::function<bool(llvm::APFloat)> floatValueFn) {
- addPredicate([position,
- floatValueFn = std::move(floatValueFn)](Operation *op) -> bool {
- std::optional<int64_t> operandNo = remapNegativeOperandNumber(position, op);
- if (!operandNo) {
- return false;
- }
-
- LLVM_DEBUG(DBGS() << "operand #" << *operandNo
- << " is a special floating point constant");
- auto cstOp =
- op->getOperand(*operandNo).getDefiningOp<arith::ConstantFloatOp>();
- if (!cstOp) {
- return false;
- }
- return floatValueFn(cstOp.value());
- });
-
- return *this;
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::operand(int64_t position, ConstantFloatOne) {
- return operand(position,
- [](llvm::APFloat value) { return value.isExactlyValue(1.0); });
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::result(transform_ext::NumEqualsTo num) {
- addPredicate([=](Operation *op) {
- LLVM_DEBUG(DBGS() << "operation has exactly " << num.value << " results");
- return num.value == op->getNumResults();
- });
- return *this;
-}
-
-transform_ext::CapturingOpMatcher &
-transform_ext::CapturingOpMatcher::result(int64_t pos,
- CapturingValueMatcher &nested) {
- addPredicate([pos, &nested](Operation *op) {
- int64_t updated = pos < 0 ? op->getNumResults() + pos : pos;
- if (updated < 0 || updated >= op->getNumResults()) {
- LLVM_DEBUG(DBGS() << "matching result #" << pos
- << " that does not exist in the operation");
- return false;
- }
- LLVM_DEBUG(DBGS() << "result #" << pos << " is");
- Value result = op->getResult(updated);
- return recursiveMatch(nested, result);
- });
- recordNestedMatcher(nested);
- return *this;
-}
-
-//===---------------------------------------------------------------------===//
-// CapturingValueMatcher
-//===---------------------------------------------------------------------===//
-
-namespace {
-struct DebugPrintValueWrapper {
- Value value;
-};
-
-llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
- const DebugPrintValueWrapper &wrapper) {
- if (auto opResult = dyn_cast<OpResult>(wrapper.value)) {
- return os << "op result #" << opResult.getResultNumber() << " in "
- << wrapper.value;
- }
-
- auto blockArg = cast<BlockArgument>(wrapper.value);
- os << "block argument #" << blockArg.getArgNumber();
- Block *parentBlock = blockArg.getParentBlock();
- Region *parentRegion = parentBlock->getParent();
- if (!parentRegion) {
- os << " of a detached block:\n";
- parentBlock->print(os);
- return os;
- }
-
- os << " of block #"
- << std::distance(parentRegion->begin(), parentBlock->getIterator());
- Operation *parentOp = parentRegion->getParentOp();
- if (!parentOp) {
- os << " of a detached region:\n";
- for (Block &b : *parentRegion) {
- b.print(os);
- }
- return os;
- }
-
- os << " in region #" << parentRegion->getRegionNumber() << " of "
- << *parentOp;
- return os;
-}
-} // namespace
-
-bool transform_ext::CapturingValueMatcher::match(Value value) {
- auto debugRAII = llvm::scope_exit([] { LLVM_DEBUG(DBGS() << "-------\n"); });
- LLVM_DEBUG(DBGS() << "matching " << DebugPrintValueWrapper{value} << "\n");
-
- if (getCaptured()) {
- LLVM_DEBUG(DBGS() << "found an already captured value: ");
- if (getCaptured() == value) {
- LLVM_DEBUG(llvm::dbgs() << "same\n");
- return true;
- } else {
- LLVM_DEBUG(llvm::dbgs() << "different\n");
- return false;
- }
- }
-
- for (const PredicateFn &fn : predicates) {
- bool result = fn(value);
- LLVM_DEBUG(llvm::dbgs() << ": " << result << "\n");
- if (!result) {
- return false;
- }
- }
-
- captured = value;
- return true;
-}
-
-transform_ext::ShapedValueMatcher::ShapedValueMatcher()
- : CapturingValueMatcher() {
- addPredicate([](Value value) {
- LLVM_DEBUG(DBGS() << "value is of shaped type");
- return value && isa<ShapedType>(value.getType());
- });
-}
-
-transform_ext::ShapedValueMatcher &
-transform_ext::ShapedValueMatcher::rank(transform_ext::CaptureRank capture) {
- addPredicate([=](Value value) {
- LLVM_DEBUG(DBGS() << "capturing shaped value rank");
- capture.value = cast<ShapedType>(value.getType()).getRank();
- return true;
- });
- return *this;
-}
-
-transform_ext::ShapedValueMatcher &
-transform_ext::ShapedValueMatcher::dim(int64_t dimension, CaptureDim capture) {
- addPredicate([=](Value value) {
- LLVM_DEBUG(DBGS() << "capturing shaped value dimension " << dimension);
- capture.value = cast<ShapedType>(value.getType()).getDimSize(dimension);
- return true;
- });
- return *this;
-}
-
-transform_ext::ShapedValueMatcher &
-transform_ext::ShapedValueMatcher::dim(AllDims tag, CaptureDims captures) {
- (void)tag;
- addPredicate([=](Value value) {
- LLVM_DEBUG(DBGS() << "capturing all shaped value dimensions");
- ArrayRef<int64_t> shape = cast<ShapedType>(value.getType()).getShape();
- captures.value.assign(shape.begin(), shape.end());
- return true;
- });
- return *this;
-}
-
-transform_ext::ShapedValueMatcher &
-transform_ext::ShapedValueMatcher::elementType(CaptureElementType captures) {
- addPredicate([=](Value value) {
- LLVM_DEBUG(DBGS() << "capturing elementType");
- captures.value = cast<ShapedType>(value.getType()).getElementType();
- return true;
- });
- return *this;
-}
-
-//===---------------------------------------------------------------------===//
-// Constraints on op rank and dims.
-//===---------------------------------------------------------------------===//
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::rank(NumGreaterEqualTo minRank) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "rank >= " << minRank.value);
- return linalgOp.getNumLoops() >= minRank.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::rank(NumLowerEqualTo maxRank) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "rank <= " << maxRank.value);
- return linalgOp.getNumLoops() <= maxRank.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::rank(NumEqualsTo exactRank) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "rank == " << exactRank.value);
- return linalgOp.getNumLoops() == exactRank.value;
- });
-}
-
-StringRef stringifyShapeKind(transform_ext::ShapeKind kind) {
- switch (kind) {
- case transform_ext::ShapeKind::Static:
- return "static";
- case transform_ext::ShapeKind::Dynamic:
- return "dynamic";
- }
- llvm_unreachable("unhandled shape kind");
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(SmallVector<int64_t> &&dimensions,
- ShapeKind kind) {
- return addPredicate([dimensions = std::move(dimensions),
- kind](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "dimensions [";
- llvm::interleaveComma(dimensions, llvm::dbgs());
- llvm::dbgs() << "] are " << stringifyShapeKind(kind));
- SmallVector<int64_t> shape = linalgOp.getStaticLoopRanges();
- for (auto dimension : dimensions) {
- int64_t transformedDimension =
- dimension >= 0 ? dimension : shape.size() + dimension;
- if (transformedDimension < 0 || transformedDimension >= shape.size()) {
- return false;
- }
- if (ShapedType::isDynamic(shape[transformedDimension]) ^
- (kind == ShapeKind::Static)) {
- continue;
- }
- return false;
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(AllDims tag, ShapeKind kind) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all dimensions are " << stringifyShapeKind(kind));
- SmallVector<int64_t> shape = linalgOp.getStaticLoopRanges();
- return llvm::all_of(shape, [=](int64_t dimension) {
- return ShapedType::isDynamic(dimension) ^ (kind == ShapeKind::Static);
- });
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(SmallVector<int64_t> &&dimensions,
- utils::IteratorType kind) {
- return addPredicate([dimensions = std::move(dimensions),
- kind](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "dimensions [";
- llvm::interleaveComma(dimensions, llvm::dbgs());
- llvm::dbgs() << "] are " << utils::stringifyIteratorType(kind));
- int64_t rank = linalgOp.getNumLoops();
- for (auto dimension : dimensions) {
- int64_t transformedDimension =
- dimension >= 0 ? dimension : rank + dimension;
- if (transformedDimension < 0 || transformedDimension >= rank) {
- return false;
- }
- utils::IteratorType iteratorKind =
- linalgOp.getIteratorTypesArray()[transformedDimension];
- if (iteratorKind == kind) {
- continue;
- }
- return false;
- }
- return true;
- });
-}
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(AllDims tag, utils::IteratorType kind) {
- return dim(AllDimsExcept({}), kind);
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(AllDimsExcept &&dims,
- utils::IteratorType kind) {
- return addPredicate([dimensions = std::move(dims),
- kind](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all dimensions except [";
- llvm::interleaveComma(dimensions.getExcluded(), llvm::dbgs());
- llvm::dbgs() << "] are " << utils::stringifyIteratorType(kind));
- int64_t rank = linalgOp.getNumLoops();
- llvm::SmallDenseSet<int64_t> excludedDims;
- for (int64_t dim : dimensions.getExcluded()) {
- excludedDims.insert(dim >= 0 ? dim : rank + dim);
- }
-
- for (auto [index, type] :
- llvm::enumerate(linalgOp.getIteratorTypesArray())) {
- if (excludedDims.contains(index)) {
- continue;
- }
- if (type == kind) {
- continue;
- }
- return false;
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(int64_t dimension,
- DivisibleBy divisibleBy) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "dimension " << dimension << " is divisible by "
- << divisibleBy.value);
- int64_t rank = linalgOp.getNumLoops();
- int64_t transformedDimension =
- dimension >= 0 ? dimension : rank + dimension;
- if (transformedDimension >= rank) {
- return false;
- }
-
- int64_t size = linalgOp.getStaticLoopRanges()[transformedDimension];
- return !ShapedType::isDynamic(size) && (size % divisibleBy.value == 0);
- });
-}
-
-//===---------------------------------------------------------------------===//
-// Capture directives.
-//===---------------------------------------------------------------------===//
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::rank(CaptureRank capture) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture rank");
- capture.value = linalgOp.getNumLoops();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(int64_t dimension, CaptureDim capture) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture dimension");
- int64_t rank = linalgOp.getNumLoops();
- int64_t transformedDimension =
- dimension >= 0 ? dimension : rank + dimension;
- if (transformedDimension >= rank) {
- return false;
- }
-
- capture.value = linalgOp.getStaticLoopRanges()[transformedDimension];
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::dim(AllDims tag, CaptureDims captures) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture all dimensions");
- captures.value = linalgOp.getStaticLoopRanges();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::indexingMaps(
- CaptureIndexingMaps indexingMaps) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture indexing maps");
- indexingMaps.value = linalgOp.getIndexingMapsArray();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::contractionDims(
- CaptureContractionDims contractionDims) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture contraction dimensions");
- StringRef convMessage = linalg::detail::getMatchContractionMessage(
- mlir::linalg::detail::isContractionInterfaceImpl(
- linalgOp, &contractionDims.value));
- if (convMessage.empty()) {
- return true;
- }
- LLVM_DEBUG(llvm::dbgs() << " (" << convMessage << ")");
- return false;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::convolutionDims(CaptureConvDims convDims) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "capture convolution dimensions");
- StringRef convMessage = linalg::detail::getMatchConvolutionMessage(
- mlir::linalg::detail::isConvolutionInterfaceImpl(linalgOp,
- &convDims.value));
- if (convMessage.empty()) {
- return true;
- }
- LLVM_DEBUG(llvm::dbgs() << " (" << convMessage << ")");
- return false;
- });
-}
-
-transform_ext::StructuredOpMatcher::StructuredOpMatcher(
- StructuredOpMatcher &A, StructuredOpMatcher &B) {
-
- addPredicate([&A, &B](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "start recursive lhs OR match {\n");
- {
- auto debugRAII = llvm::scope_exit(
- [] { LLVM_DEBUG(DBGS() << "} end recursive match"); });
- if (A.match(linalgOp)) {
- return true;
- }
- }
- LLVM_DEBUG(DBGS() << "start recursive rhs OR match {\n");
- {
- auto debugRAII = llvm::scope_exit(
- [] { LLVM_DEBUG(DBGS() << "} end recursive match"); });
- if (B.match(linalgOp)) {
- return true;
- }
- }
- return false;
- });
- recordNestedMatcher(A);
- recordNestedMatcher(B);
-}
-
-//===---------------------------------------------------------------------===//
-// Constraints on input operands.
-//===---------------------------------------------------------------------===//
-
-void transform_ext::StructuredOpMatcher::addInputMatcher(
- int64_t position, std::function<bool(Operation *)> matcher,
- OptionalMatch optional) {
- addInputMatcher(
- position,
- // No need to handle optional inside the lambda, the wrapper will do that.
- [matcher = std::move(matcher)](Value value) {
- Operation *definingOp = value.getDefiningOp();
- return definingOp && matcher(definingOp);
- },
- optional);
-}
-
-void transform_ext::StructuredOpMatcher::addInputMatcher(
- int64_t position, std::function<bool(Value)> matcher,
- OptionalMatch optional) {
- addPredicate([position, optional, matcher = std::move(matcher)](
- linalg::LinalgOp linalgOp) -> bool {
- int64_t transformedPosition =
- position >= 0 ? position : linalgOp.getNumDpsInputs() + position;
- if (transformedPosition >= linalgOp.getNumDpsInputs()) {
- LLVM_DEBUG(DBGS() << "input operand #" << position
- << " does not exist but match required");
- return false;
- }
-
- LLVM_DEBUG(DBGS() << "input operand #" << position
- << (optional.value ? " (optional match) " : " ")
- << "is\n");
-
- // We MUST run the matcher at this point, even if the match is optional,
- // to allow for capture.
- LLVM_DEBUG(DBGS() << "start recursive match {\n");
- auto debugRAII =
- llvm::scope_exit([] { LLVM_DEBUG(DBGS() << "} end recursive match"); });
- if (matcher(linalgOp.getDpsInputOperand(transformedPosition)->get())) {
- return true;
- }
- return optional.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(AllOperands tag, IsPermutation) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all input operands have permutation maps");
- // all_of with a lambda requires const-casting dance, so using a loop.
- for (OpOperand *operand : linalgOp.getDpsInputOperands()) {
- if (!linalgOp.getMatchingIndexingMap(operand).isPermutation()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(AllOperands tag,
- IsProjectedPermutation) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all input operands have projected permutation maps");
- // all_of with a lambda requires const-casting dance, so using a loop.
- for (OpOperand *operand : linalgOp.getDpsInputOperands()) {
- if (!linalgOp.getMatchingIndexingMap(operand).isProjectedPermutation()) {
- return false;
- }
- }
- return true;
- });
-}
-
-/// Helper to check if the map is an identity map with a projected dim.
-static bool isProjectedMap(AffineMap map, int64_t projectedDim) {
- if (!map.isProjectedPermutation()) {
- return false;
- }
- int64_t dimCounter = 0;
- for (unsigned i = 0, e = map.getNumResults(); i < e; i++) {
- // Skip the project dim.
- if (dimCounter == projectedDim) {
- dimCounter++;
- }
- if (map.getDimPosition(i) != dimCounter++) {
- return false;
- }
- }
- return true;
-}
-
-/// Helper to turn a potentially negative index to positive within the range
-/// [0, ub) and indicate whether the transformed index is in bounds.
-static bool makeValidPositiveIndex(int64_t &index, int64_t ub) {
- int64_t positiveIndex = index >= 0 ? index : ub + index;
- if (positiveIndex < 0 || ub < positiveIndex) {
- LLVM_DEBUG(DBGSNL() << " index out of range");
- return false;
- }
- index = positiveIndex;
- return true;
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(SmallVector<int64_t> &&positions,
- IsProjected dim) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "operands ";
- llvm::interleaveComma(positions, llvm::dbgs());
- llvm::dbgs() << " have a permutation maps with " << dim.value
- << " projected");
- int64_t updatedDim = dim.value;
- if (!makeValidPositiveIndex(updatedDim, linalgOp.getNumLoops())) {
- return false;
- }
- for (int64_t position : positions) {
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition,
- linalgOp.getNumDpsInputs())) {
- return false;
- }
- OpOperand *operand = linalgOp.getDpsInputOperand(updatedPosition);
- if (!isProjectedMap(linalgOp.getMatchingIndexingMap(operand),
- updatedDim)) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(AllOperands tag, IsIdentity) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all input operands have identity maps");
- // all_of with a lambda requires const-casting dance, so using a loop.
- for (OpOperand *operand : linalgOp.getDpsInputOperands()) {
- if (!linalgOp.getMatchingIndexingMap(operand).isIdentity()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(SmallVector<int64_t> &&positions,
- IsIdentity) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "input operands ";
- llvm::interleaveComma(positions, llvm::dbgs());
- llvm::dbgs() << " have identity maps");
- // all_of with a lambda requires const-casting dance, so using a loop.
- for (int64_t position : positions) {
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition,
- linalgOp.getNumDpsInputs())) {
- return false;
- }
- OpOperand *operand = linalgOp.getDpsInputOperand(updatedPosition);
- if (!linalgOp.getMatchingIndexingMap(operand).isIdentity()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(int64_t position,
- ElementTypeBitWidth width) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "input operand #" << position
- << " has elemental type with bit width " << width.value);
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInputs())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInputOperand(updatedPosition)->get().getType());
- return shapedType && shapedType.getElementType().isIntOrFloat() &&
- shapedType.getElementType().getIntOrFloatBitWidth() == width.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(int64_t position,
- CaptureElementTypeBitWidth width) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "input operand #" << position << " capture bitwidth");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInputs())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInputOperand(updatedPosition)->get().getType());
- if (!shapedType || !shapedType.getElementType().isIntOrFloat()) {
- return false;
- }
- width.value = shapedType.getElementType().getIntOrFloatBitWidth();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(int64_t position,
- CaptureElementType elem) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "input operand #" << position
- << " capture element type");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInputs())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInputOperand(updatedPosition)->get().getType());
- if (!shapedType) {
- LLVM_DEBUG(DBGSNL() << " not a shaped type");
- return false;
- }
- elem.value = shapedType.getElementType();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(NumEqualsTo num) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "number of input operands == " << num.value);
- return linalgOp.getNumDpsInputs() == num.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(int64_t position,
- ConstantFloatMinOrMinusInf) {
- return input(position, [](llvm::APFloat f) {
- return (f.isLargest() || f.isInfinity()) && f.isNegative();
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::input(int64_t position, ConstantFloatZero) {
- return input(position, [](llvm::APFloat f) { return f.isZero(); });
-}
-
-transform_ext::StructuredOpMatcher &transform_ext::StructuredOpMatcher::input(
- int64_t position, std::function<bool(llvm::APFloat)> floatValueFn) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "input operand #" << position
- << " is a special floating point constant");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInputs())) {
- return false;
- }
- auto cstOp = linalgOp.getDpsInputOperand(updatedPosition)
- ->get()
- .getDefiningOp<arith::ConstantFloatOp>();
- if (!cstOp) {
- return false;
- }
- return floatValueFn(cstOp.value());
- });
-}
-
-//===---------------------------------------------------------------------===//
-// Constraints on output operands.
-//===---------------------------------------------------------------------===//
-
-void transform_ext::StructuredOpMatcher::addOutputMatcher(
- int64_t position, std::function<bool(Operation *)> matcher,
- OptionalMatch optional) {
- addPredicate([position, optional, matcher = std::move(matcher)](
- linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "output operand #" << position
- << (optional.value ? " (optional match) "
- : " (mandatory match) ")
- << "is produced by\n");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInits())) {
- return false;
- }
- Operation *definingOp =
- linalgOp.getDpsInitOperand(updatedPosition)->get().getDefiningOp();
- if (!definingOp) {
- return optional.value;
- }
- // We MUST run the matcher at this point, even if the match is optional,
- // to allow for capture.
- LLVM_DEBUG(DBGS() << "start recursive match {\n");
- auto debugRAII =
- llvm::scope_exit([] { LLVM_DEBUG(DBGS() << "} end recursive match"); });
- if (matcher(definingOp)) {
- return true;
- }
- return optional.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(AllOperands tag, IsPermutation) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all output operands have permutation maps");
- for (OpOperand &operand : linalgOp.getDpsInitsMutable()) {
- if (!linalgOp.getMatchingIndexingMap(&operand).isPermutation()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(AllOperands tag,
- IsProjectedPermutation) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all output operands have projected permutation maps");
- for (OpOperand &operand : linalgOp.getDpsInitsMutable()) {
- if (!linalgOp.getMatchingIndexingMap(&operand).isProjectedPermutation()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(AllOperands tag, IsProjected dim) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all output operands have a maps with projected");
- int64_t updatedDim = dim.value;
- if (!makeValidPositiveIndex(updatedDim, linalgOp.getNumLoops())) {
- return false;
- }
- // all_of with a lambda requires const-casting dance, so using a loop.
- for (OpOperand &operand : linalgOp.getDpsInitsMutable()) {
- if (!isProjectedMap(linalgOp.getMatchingIndexingMap(&operand),
- updatedDim)) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(AllOperands tag, IsIdentity) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "all output operands have identity permutation maps");
- for (OpOperand &operand : linalgOp.getDpsInitsMutable()) {
- if (!linalgOp.getMatchingIndexingMap(&operand).isIdentity()) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(int64_t position,
- ElementTypeBitWidth width) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "output operand #" << position
- << " has elemental type with bit width " << width.value);
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInits())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInitOperand(updatedPosition)->get().getType());
- return shapedType && shapedType.getElementType().isIntOrFloat() &&
- shapedType.getElementType().getIntOrFloatBitWidth() == width.value;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(int64_t position,
- CaptureElementTypeBitWidth width) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "output operand #" << position << " capture bitwidth");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInits())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInitOperand(updatedPosition)->get().getType());
- if (!shapedType || !shapedType.getElementType().isIntOrFloat()) {
- LLVM_DEBUG(DBGSNL() << " could not infer element type");
- return false;
- }
- width.value = shapedType.getElementType().getIntOrFloatBitWidth();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(int64_t position,
- CaptureElementType elem) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "output operand #" << position
- << " capture element type");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInits())) {
- return false;
- }
- auto shapedType = dyn_cast<ShapedType>(
- linalgOp.getDpsInitOperand(updatedPosition)->get().getType());
- if (!shapedType) {
- LLVM_DEBUG(DBGSNL() << " not a shaped type");
- return false;
- }
- elem.value = shapedType.getElementType();
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(int64_t position,
- SingleCombinerReduction tag) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "output operand #" << position
- << " is populated by a single-combiner reduction");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp.getNumDpsInits())) {
- return false;
- }
- SmallVector<Operation *> combinerOps;
- return matchReduction(linalgOp.getRegionOutputArgs(), updatedPosition,
- combinerOps) &&
- llvm::hasSingleElement(combinerOps);
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::output(NumEqualsTo num) {
- return addPredicate([=](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "number of output operands == " << num.value);
- return linalgOp.getNumDpsInits() == num.value;
- });
-}
-
-//===---------------------------------------------------------------------===//
-// Constraints on results.
-//===---------------------------------------------------------------------===//
-
-void transform_ext::StructuredOpMatcher::addResultMatcher(
- int64_t position, HasAnyUse tag, std::function<bool(Operation *)> matcher,
- OptionalMatch optional) {
- addPredicate([matcher = std::move(matcher), optional,
- position](linalg::LinalgOp linalgOp) -> bool {
- LLVM_DEBUG(DBGS() << "result #" << position
- << (optional.value ? " (optional match) "
- : " (mandatory match) ")
- << "has a use\n");
- int64_t updatedPosition = position;
- if (!makeValidPositiveIndex(updatedPosition, linalgOp->getNumResults())) {
- return false;
- }
-
- // We MUST run the matcher at this point, even if the match is optional,
- // to allow for capture.
- LLVM_DEBUG(DBGS() << "start recursive match {\n");
- auto debugRAII =
- llvm::scope_exit([] { LLVM_DEBUG(DBGS() << "} end recursive match"); });
- if (llvm::any_of(linalgOp->getResult(updatedPosition).getUsers(),
- [&matcher](Operation *op) { return matcher(op); })) {
- return true;
- }
- return optional.value;
- });
-}
-
-//===-------------------------------------------------------------------===//
-// Constraints on op region.
-//===-------------------------------------------------------------------===//
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::singleOpWithCanonicaleArgs(
- StringRef opcode, bool commutative) {
- return addPredicate([=](linalg::LinalgOp linalgOp) {
- if (linalgOp.getBlock()->getOperations().size() != 2) {
- return false;
- }
- Operation *innerOp = &(*linalgOp.getBlock()->getOperations().begin());
- if (innerOp->getName().getStringRef() != opcode ||
- innerOp->getNumResults() != 1) {
- return false;
- }
- Operation *yieldOp = linalgOp.getBlock()->getTerminator();
- if (yieldOp->getNumOperands() != 1) {
- return false;
- }
- if (yieldOp->getOperand(0).getDefiningOp() != innerOp) {
- return false;
- }
- if (commutative && innerOp->getNumOperands() == 2) {
- auto arg0 = dyn_cast<BlockArgument>(innerOp->getOperand(0));
- auto arg1 = dyn_cast<BlockArgument>(innerOp->getOperand(1));
- if (!arg0 || !arg1) {
- return false;
- }
- if (arg0.getParentBlock() != linalgOp.getBlock() ||
- arg1.getParentBlock() != linalgOp.getBlock()) {
- return false;
- }
- if (!((arg0.getArgNumber() == 0 && arg1.getArgNumber() == 1) ||
- (arg1.getArgNumber() == 0 && arg0.getArgNumber() == 1))) {
- return false;
- }
- } else {
- for (auto [index, operand] : llvm::enumerate(innerOp->getOperands())) {
- auto arg = dyn_cast<BlockArgument>(operand);
- if (!arg || arg.getParentBlock() != linalgOp.getBlock() ||
- arg.getArgNumber() != index) {
- return false;
- }
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::isFloatReciprocal() {
- return addPredicate([=](linalg::LinalgOp linalgOp) {
- LLVM_DEBUG(DBGS() << "op region represents a reciprocal operation");
- if (linalgOp.getBlock()->getOperations().size() != 2) {
- return false;
- }
- Operation *innerOp = &(*linalgOp.getBlock()->getOperations().begin());
- if (!isa<arith::DivFOp>(innerOp) || innerOp->getNumResults() != 1) {
- return false;
- }
- Operation *yieldOp = linalgOp.getBlock()->getTerminator();
- if (yieldOp->getNumOperands() != 1) {
- return false;
- }
- if (yieldOp->getOperand(0).getDefiningOp() != innerOp) {
- return false;
- }
- auto cst = innerOp->getOperand(0).getDefiningOp<arith::ConstantFloatOp>();
- if (!cst || cst.value().convertToDouble() != 1.0) {
- return false;
- }
- auto arg = dyn_cast<BlockArgument>(innerOp->getOperand(1));
- if (!arg || arg.getParentBlock() != linalgOp.getBlock() ||
- arg.getArgNumber() != 0) {
- return false;
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::passThroughOp() {
- return addPredicate([=](linalg::LinalgOp linalgOp) {
- if (linalgOp.getBlock()->getOperations().size() != 1) {
- return false;
- }
- Operation *yieldOp = linalgOp.getBlock()->getTerminator();
- for (auto [index, operand] : llvm::enumerate(yieldOp->getOperands())) {
- auto arg = dyn_cast<BlockArgument>(operand);
- if (!arg || arg.getParentBlock() != linalgOp.getBlock() ||
- arg.getArgNumber() != index) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::StructuredOpMatcher &
-transform_ext::StructuredOpMatcher::hasContractionBody(
- function_ref<bool(Operation *)> isaElemOpTy,
- function_ref<bool(Operation *)> isaReductionOpTy, StringRef elemOpName,
- StringRef reductionOpName) {
- return addPredicate([=](linalg::LinalgOp linalgOp) {
- LLVM_DEBUG(DBGS() << "op region is a " << elemOpName << "/"
- << reductionOpName << " contraction (");
- auto scopeExitPrinter =
- llvm::scope_exit([] { LLVM_DEBUG(llvm::dbgs() << " check failed)"); });
-
- Block *body = linalgOp.getBlock();
- if (!llvm::hasNItems(*body, 3)) {
- LLVM_DEBUG(llvm::dbgs() << "three-operation body");
- return false;
- }
- if (body->getNumArguments() != 3) {
- LLVM_DEBUG(llvm::dbgs() << "three-argument block");
- return false;
- }
-
- Operation *elemOp = &(*linalgOp.getBlock()->getOperations().begin());
- Operation *reductionOp = elemOp->getNextNode();
- Operation *yieldOp = reductionOp->getNextNode();
- if (!isaElemOpTy(elemOp)) {
- LLVM_DEBUG(llvm::dbgs() << "first operation is a " << elemOpName);
- return false;
- }
- if (!isaReductionOpTy(reductionOp)) {
- LLVM_DEBUG(llvm::dbgs() << "second operation is a " << reductionOpName);
- return false;
- }
- if (yieldOp->getNumOperands() != 1) {
- LLVM_DEBUG(llvm::dbgs() << "one value yielded");
- return false;
- }
- if (yieldOp->getOperand(0).getDefiningOp() != reductionOp) {
- LLVM_DEBUG(llvm::dbgs() << "yielded value produced by the second op");
- return false;
- }
- if (elemOp->getNumOperands() != 2 || elemOp->getNumResults() != 1) {
- LLVM_DEBUG(llvm::dbgs() << "first op has two operands and one result");
- return false;
- }
- if (reductionOp->getNumOperands() != 2 ||
- reductionOp->getNumResults() != 1) {
- LLVM_DEBUG(llvm::dbgs() << "second op has two operands and one result");
- return false;
- }
-
- SmallVector<Value, 2> expectedReductionOperands = {body->getArgument(2),
- elemOp->getResult(0)};
- if (!llvm::equal(expectedReductionOperands, reductionOp->getOperands()) &&
- !llvm::equal(llvm::reverse(expectedReductionOperands),
- reductionOp->getOperands())) {
- LLVM_DEBUG(llvm::dbgs() << "operands of the second op");
- return false;
- }
-
- ValueRange expectedElemOperands = body->getArguments().take_front(2);
- if (!llvm::equal(expectedElemOperands, elemOp->getOperands()) &&
- !llvm::equal(llvm::reverse(expectedElemOperands),
- elemOp->getOperands())) {
- LLVM_DEBUG(llvm::dbgs() << "operands of the first op");
- return false;
- }
-
- scopeExitPrinter.release();
- LLVM_DEBUG(llvm::dbgs() << "success)");
- return true;
- });
-}
-
-void transform_ext::detail::debugOutputForConcreteOpMatcherConstructor(
- StringRef name) {
- LLVM_DEBUG(DBGS() << "op is a " << name << "'");
-}
-
-//===---------------------------------------------------------------------===//
-// TensorPadOpMatcher
-//===---------------------------------------------------------------------===//
-
-transform_ext::TensorPadOpMatcher &
-transform_ext::TensorPadOpMatcher::low(ArrayRef<int64_t> sizes) {
- return addPredicate([=](tensor::PadOp tensorPad) {
- LLVM_DEBUG({
- DBGS() << "low pad sizes are ";
- llvm::interleaveComma(sizes, llvm::dbgs());
- });
- for (auto [ofr, sz] : llvm::zip(tensorPad.getMixedLowPad(), sizes)) {
- if (isConstantIntValue(ofr, sz)) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::TensorPadOpMatcher &
-transform_ext::TensorPadOpMatcher::low(AllDims tag, int64_t size) {
- return addPredicate([=](tensor::PadOp tensorPad) {
- LLVM_DEBUG(DBGS() << "all low pad sizes are " << size);
- return llvm::all_of(tensorPad.getMixedLowPad(), [&](OpFoldResult ofr) {
- return isConstantIntValue(ofr, size);
- });
- });
-}
-
-transform_ext::TensorPadOpMatcher &
-transform_ext::TensorPadOpMatcher::high(ArrayRef<int64_t> sizes) {
- return addPredicate([=](tensor::PadOp tensorPad) {
- LLVM_DEBUG({
- DBGS() << "high pad sizes are ";
- llvm::interleaveComma(sizes, llvm::dbgs());
- });
- for (auto [ofr, sz] : llvm::zip(tensorPad.getMixedHighPad(), sizes)) {
- if (isConstantIntValue(ofr, sz)) {
- return false;
- }
- }
- return true;
- });
-}
-
-transform_ext::TensorPadOpMatcher &
-transform_ext::TensorPadOpMatcher::high(AllDims tag, int64_t size) {
- return addPredicate([=](tensor::PadOp tensorPad) {
- LLVM_DEBUG(DBGS() << "all high pad sizes are " << size);
- return llvm::all_of(tensorPad.getMixedHighPad(), [&](OpFoldResult ofr) {
- return isConstantIntValue(ofr, size);
- });
- });
-}
-
-transform_ext::TensorPadOpMatcher &
-transform_ext::TensorPadOpMatcher::yieldsExternalValue() {
- return addPredicate([=](tensor::PadOp tensorPad) {
- LLVM_DEBUG(DBGS() << "pad body yields an externally-defined value");
- Block *body = tensorPad.getBody();
- if (!llvm::hasSingleElement(*body)) {
- return false;
- }
- return llvm::all_of(body->getTerminator()->getOperands(),
- [body](Value operand) {
- auto arg = dyn_cast<BlockArgument>(operand);
- return !arg || arg.getOwner() != body;
- });
- });
-}
-
-//===---------------------------------------------------------------------===//
-// MatchCallbackResult.
-//===---------------------------------------------------------------------===//
-
-ArrayRef<Operation *>
-transform_ext::MatchCallbackResult::getPayloadGroup(int64_t position) const {
- assert(position < payloadGroupLengths.size());
- int64_t start = 0;
- for (int64_t i = 0; i < position; ++i) {
- start += payloadGroupLengths[i];
- }
- return llvm::ArrayRef(payloadOperations)
- .slice(start, payloadGroupLengths[position]);
-}
-
-//===---------------------------------------------------------------------===//
-// Case-specific matcher builders.
-//===---------------------------------------------------------------------===//
-
-static constexpr int64_t kCudaWarpSize = 32;
-
-void transform_ext::makeReductionMatcher(
- transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&reductionCapture,
- transform_ext::StructuredOpMatcher *&fillCapture,
- transform_ext::StructuredOpMatcher *&leadingCapture,
- transform_ext::StructuredOpMatcher *&trailingCapture,
- MatchedReductionCaptures &captures, bool mustMatchEntireFunc) {
- // The core part of the matcher is anchored on a particular reduction op.
- auto &reduction =
- m_StructuredOp(matcherContext)
- // Op has at least a parallel a reduction dimension and at
- // most 3 parallel dimensions.
- // TODO: relax once we have global collapse/expand_shape.
- //
- .rank(NumGreaterEqualTo(2))
- .rank(NumLowerEqualTo(4))
- .rank(CaptureRank(captures.reductionRank))
- // Op has a single most-minor reduction.
- .dim(-1, utils::IteratorType::reduction)
- // Capture op sizes.
- .dim(AllDims(), CaptureDims(captures.reductionOpSizes))
- // All other dimensions are parallel.
- .dim(AllDimsExcept({-1}), utils::IteratorType::parallel)
- // Single input for now, can be arbitrary projected permutations.
- // TODO: Multiple inputs, can be arbitrary projected permutations.
- // TODO: Watch out for multiple inputs though as a reduction turns
- // into a contraction when mixed with projected
- // permutations. A reduction is often bandwidth bound but
- // contraction is a different beast that is compute bound
- // and has a very different schedule.
- //
- .input(NumEqualsTo(1))
- .input(AllOperands(), IsProjectedPermutation())
- // Single output supported atm.
- // TODO: Multiple outputs.
- //
- .output(NumEqualsTo(1))
- // A reduction output must be a projected permutation, match it but we
- // could also drop this technically.
- .output(AllOperands(), IsProjectedPermutation())
- // Only single combiner for now due to reduction warp
- // distribution.
- // TODO: relax this once reduction distribution is more powerful.
- //
- .output(0, CaptureElementTypeBitWidth(
- captures.reductionOutputElementalTypeBitWidth))
- .output(0, SingleCombinerReduction());
- reductionCapture = &reduction;
-
- // Mandatory FillOp must create the unique output of the reduction.
- // TODO: Relax this, as any map, broadcast, transpose should also work.
- //
- auto &fill = m_StructuredOp<linalg::FillOp>(matcherContext);
- reduction = reduction.output(NumEqualsTo(1)).output(0, fill);
- fillCapture = &fill;
-
- // Optional leading or trailing op can be any map, transpose, broadcast but
- // not reduce or windowing operation for now.
- // It must create the unique input for the reduction.
- // TODO: match more optional leading ops, one per input of the reduction.
- // TODO: careful about multi-output and turning into a contraction.
- //
- transform_ext::StructuredOpMatcher commonLeadingOrTrailing =
- m_StructuredOp<linalg::GenericOp>(matcherContext)
- // All parallel dimensions.
- .dim(AllDims(), utils::IteratorType::parallel)
- // All inputs are any projected permutation.
- .input(AllOperands(), IsProjectedPermutation())
- .output(AllOperands(), IsPermutation())
- // leading and trailing may have 0, 1 or more input as long as they do
- // not come from unmatched ops. This extra constraint is taken care of
- // separately. This is also a noop but we document it.
- // TODO: Base and derived classes, atm this does not compile.
- // .input(NumGreaterEqualTo(0))
- // Single output supported atm.
- // TODO: extend this.
- //
- .output(NumEqualsTo(1));
- // TODO: match more optional leading ops, one per input of the reduction.
- // TODO: careful about multi-output and turning into a contraction.
- //
- auto &leading =
- m_StructuredOp(matcherContext, commonLeadingOrTrailing)
- .rank(CaptureRank(captures.maybeLeadingRank))
- // Capture op sizes.
- .dim(AllDims(), CaptureDims(captures.leadingOpSizes))
- // Capture output elemental type.
- .output(0, CaptureElementTypeBitWidth(
- captures.maybeLeadingOutputElementalTypeBitWidth));
- reduction = reduction.input(0, leading, OptionalMatch());
- leadingCapture = &leading;
-
- // Optional trailing can be any map, transpose, broadcast but not reduce or
- // windowing operation for now.
- // It must be fed by the unique input for the reduction.
- // TODO: match more optional leading ops, one per input of the reduction.
- // TODO: careful about multi-output and turning into a contraction.
- //
- auto &trailing =
- m_StructuredOp(matcherContext, commonLeadingOrTrailing)
- .rank(CaptureRank(captures.maybeTrailingRank))
- // Capture op sizes.
- .dim(AllDims(), CaptureDims(captures.trailingOpSizes))
- // Capture output elemental type.
- .output(0, CaptureElementTypeBitWidth(
- captures.maybeTrailingOutputElementalTypeBitWidth));
- reduction = reduction.result(0, HasAnyUse(), trailing, OptionalMatch());
- if (mustMatchEntireFunc) {
- reduction = reduction.allTilableOpsCaptured<mlir::FunctionOpInterface>();
- }
- trailingCapture = &trailing;
-}
-
-void transform_ext::makeReductionMatcher(transform_ext::MatcherContext &context,
- StructuredOpMatcher *&reductionCapture,
- MatchedReductionCaptures &captures,
- bool mustMatchEntireFunc) {
- StructuredOpMatcher *fill;
- StructuredOpMatcher *leading;
- StructuredOpMatcher *trailing;
- makeReductionMatcher(context, reductionCapture, fill, leading, trailing,
- captures, mustMatchEntireFunc);
-}
-
-void transform_ext::makeMatmulMatcher(
- transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&matmulCapture,
- transform_ext::StructuredOpMatcher *&fillCapture,
- transform_ext::StructuredOpMatcher *&trailingCapture,
- transform_ext::MatchedMatmulCaptures &captures, bool mustMatchEntireFunc) {
- auto &matmul = transform_ext::m_StructuredOp<linalg::MatmulOp>(matcherContext)
- // Capture op sizes.
- .dim(AllDims(), CaptureDims(captures.matmulOpSizes))
- // Capture input/output element types.
- .input(0, CaptureElementType(captures.lhsElementType))
- .input(1, CaptureElementType(captures.rhsElementType))
- .output(0, CaptureElementType(captures.outputElementType));
- matmulCapture = &matmul;
- // Mandatory FillOp must create the unique output of the reduction.
- auto &fill = transform_ext::m_StructuredOp<linalg::FillOp>(matcherContext);
- matmul = matmul.output(transform_ext::NumEqualsTo(1)).output(0, fill);
- fillCapture = &fill;
-
- auto &trailing = m_StructuredOp<linalg::GenericOp>(matcherContext);
- matmul = matmul.result(0, HasAnyUse(), trailing, OptionalMatch());
- if (mustMatchEntireFunc) {
- matmul = matmul.allTilableOpsCaptured<mlir::FunctionOpInterface>();
- }
- trailingCapture = &trailing;
-}
-
-void transform_ext::makeBatchMatmulMatcher(
- transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&bmmCapture,
- transform_ext::StructuredOpMatcher *&fillCapture,
- transform_ext::MatchedMatmulCaptures &captures, bool mustMatchEntireFunc) {
- auto &bmm =
- transform_ext::m_StructuredOp<linalg::BatchMatmulOp, linalg::GenericOp>(
- matcherContext)
- .hasContractionBody<arith::MulFOp, arith::AddFOp>()
- .rank(NumEqualsTo(4))
- .dim(AllDims(), CaptureDims(captures.matmulOpSizes))
- .dim(AllDimsExcept({-1}), utils::IteratorType::parallel)
- .dim(-1, utils::IteratorType::reduction)
- .contractionDims(CaptureContractionDims(captures.contractionDims))
- .input(NumEqualsTo(2))
- .input(0, CaptureElementType(captures.lhsElementType))
- .input(1, CaptureElementType(captures.rhsElementType))
- .output(0, CaptureElementType(captures.outputElementType));
- bmmCapture = &bmm;
-
- auto &fill = transform_ext::m_StructuredOp<linalg::FillOp>(matcherContext);
- bmm = bmm.output(0, fill);
- fillCapture = &fill;
-
- if (mustMatchEntireFunc) {
- bmm = bmm.allTilableOpsCaptured<mlir::FunctionOpInterface>();
- }
-}
-
-/// Match sum(%src, broadcast(%reduction))
-static void
-matchSubBroadcast(transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher &maxReduction,
- transform_ext::CapturingValueMatcher &softmaxSourceOperand,
- transform_ext::StructuredOpMatcher *&sub) {
- using namespace transform_ext;
-
- auto &broadcast =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .passThroughOp()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(0, IsProjected(-1))
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
- broadcast = broadcast.input(0, maxReduction);
-
- auto &subParallel =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::SubFOp>()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(2))
- .input(0, IsIdentity())
- .input(1, IsIdentity())
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
- subParallel = subParallel.input(0, softmaxSourceOperand);
- subParallel = subParallel.input(1, broadcast);
-
- auto &subBroadcast =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::SubFOp>()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(2))
- .input(0, IsIdentity())
- .input(1, IsProjected(-1))
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
- subBroadcast = subBroadcast.input(0, softmaxSourceOperand);
- subBroadcast = subBroadcast.input(1, maxReduction);
- auto &subOr = transform_ext::m_StructuredOp_Or(matcherContext, subBroadcast,
- subParallel);
- sub = &subOr;
-}
-
-/// Match sum(%exp, broadcast(%sum))
-static void matchdivBroadcast(transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher &expOperand,
- transform_ext::StructuredOpMatcher &sum,
- transform_ext::StructuredOpMatcher *&div) {
- using namespace transform_ext;
-
- auto &broadcast =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .passThroughOp()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(0, IsProjected(-1))
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
- broadcast = broadcast.input(0, sum);
-
- auto &divNoBroadcast =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::DivFOp>()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(2))
- .input(0, IsIdentity())
- .input(1, IsIdentity())
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
-
- divNoBroadcast = divNoBroadcast.input(0, expOperand);
- divNoBroadcast = divNoBroadcast.input(1, broadcast);
-
- auto &divBroadcast =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::DivFOp>()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(2))
- .input(0, IsIdentity())
- .input(1, IsProjected(-1))
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
-
- divBroadcast = divBroadcast.input(0, expOperand);
- divBroadcast = divBroadcast.input(1, sum);
-
- auto &divMerge = transform_ext::m_StructuredOp_Or(
- matcherContext, divNoBroadcast, divBroadcast);
- div = &divMerge;
-}
-
-void transform_ext::makeSoftmaxMatcher(
- transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&maxReductionCapture,
- transform_ext::StructuredOpMatcher *&softmaxRootCapture) {
- auto &softmaxSourceOperand = m_Value(matcherContext);
-
- auto &fillMinusInf = m_StructuredOp<linalg::FillOp>(matcherContext)
- .input(0, ConstantFloatMinOrMinusInf());
- auto &maxReduction =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::MaximumFOp>(/*commutative=*/true)
- // Only handle most inner reduction for now.
- .dim(-1, utils::IteratorType::reduction)
- .dim(AllDimsExcept({-1}), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(AllOperands(), IsIdentity())
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsProjected(-1));
- maxReduction = maxReduction.input(0, softmaxSourceOperand);
- maxReduction = maxReduction.output(0, fillMinusInf);
- maxReductionCapture = &maxReduction;
-
- transform_ext::StructuredOpMatcher *subOperand;
- matchSubBroadcast(matcherContext, maxReduction, softmaxSourceOperand,
- subOperand);
-
- auto &expOperand = m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<math::ExpOp>()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(AllOperands(), IsIdentity())
- .output(AllOperands(), IsIdentity())
- .output(NumEqualsTo(1));
- expOperand = expOperand.input(0, *subOperand);
-
- auto &fillZero = m_StructuredOp<linalg::FillOp>(matcherContext)
- .input(0, ConstantFloatZero());
- auto &sum =
- m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::AddFOp>(/*commutative=*/true)
- // Only handle most inner reduction for now.
- .dim(-1, utils::IteratorType::reduction)
- .dim(AllDimsExcept({-1}), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(AllOperands(), IsIdentity())
- .output(AllOperands(), IsProjected(-1))
- .output(NumEqualsTo(1));
- sum = sum.input(0, expOperand);
- sum = sum.output(0, fillZero);
-
- auto &rcpOperand = m_StructuredOp<linalg::GenericOp>(matcherContext)
- .isFloatReciprocal()
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(1))
- .input(AllOperands(), IsIdentity())
- .output(AllOperands(), IsIdentity())
- .output(NumEqualsTo(1));
- rcpOperand = rcpOperand.input(0, sum);
-
- auto &mulOperand =
- transform_ext::m_StructuredOp<linalg::GenericOp>(matcherContext)
- .singleOpWithCanonicaleArgs<arith::MulFOp>(/*commutative=*/true)
- .dim(AllDims(), utils::IteratorType::parallel)
- .input(NumEqualsTo(2))
- .input(0, IsIdentity())
- .input(1, IsProjected(-1))
- .output(NumEqualsTo(1))
- .output(AllOperands(), IsIdentity());
-
- mulOperand = mulOperand.input(0, expOperand);
- mulOperand = mulOperand.input(1, rcpOperand);
-
- transform_ext::StructuredOpMatcher *divOperand;
- matchdivBroadcast(matcherContext, expOperand, sum, divOperand);
-
- auto &softmaxRoot =
- transform_ext::m_StructuredOp_Or(matcherContext, mulOperand, *divOperand);
- softmaxRootCapture = &softmaxRoot;
-}
-
-/// Matcher for convolutions.
-void transform_ext::makeConvolutionMatcher(
- transform_ext::MatcherContext &matcherContext,
- transform_ext::StructuredOpMatcher *&convolutionCapture,
- transform_ext::StructuredOpMatcher *&fillCapture,
- transform_ext::StructuredOpMatcher *&trailingCapture,
- MatchedConvolutionCaptures &captures, bool mustMatchEntireFunc) {
- // The core part of the matcher is anchored on a particular convolution op.
- auto &convolution =
- m_StructuredOp<linalg::Conv2DNchwFchwOp, linalg::Conv2DNhwcHwcfOp>(
- matcherContext)
- // Capture convolution dim classifications.
- .convolutionDims(CaptureConvDims(captures.convolutionDims))
- // Capture op sizes.
- .dim(AllDims(), CaptureDims(captures.convolutionOpSizes))
- // Capture convolution element types.
- .input(0, CaptureElementType(captures.inputElementType))
- .input(1, CaptureElementType(captures.filterElementType))
- .output(0, CaptureElementType(captures.outputElementType));
- convolutionCapture = &convolution;
-
- // Optional FillOp to create the unique output of the convolution.
- auto &fill = m_StructuredOp<linalg::FillOp>(matcherContext)
- .output(0, CaptureElementTypeBitWidth(
- captures.maybeFillElementalTypeBitWidth));
- convolution =
- convolution.output(NumEqualsTo(1)).output(0, fill, OptionalMatch());
- fillCapture = &fill;
-
- // Optional trailing op can be any map, transpose, broadcast but
- // not reduce or windowing operation for now.
- // It must create the unique input for the reduction.
- auto &trailing =
- m_StructuredOp<linalg::GenericOp>(matcherContext)
- // All parallel dimensions.
- .dim(AllDims(), utils::IteratorType::parallel)
- // All inputs are any projected permutation.
- .input(AllOperands(), IsProjectedPermutation())
- .output(AllOperands(), IsPermutation())
- .output(NumEqualsTo(1))
- .dim(AllDims(), CaptureDims(captures.trailingOpSizes))
- // Capture output elemental type.
- .output(0, CaptureElementTypeBitWidth(
- captures.maybeTrailingOutputElementalTypeBitWidth));
-
- // Optional trailing can be any map, transpose, broadcast but not reduce or
- // windowing operation for now.
- convolution = convolution.result(0, HasAnyUse(), trailing, OptionalMatch());
- if (mustMatchEntireFunc) {
- convolution =
- convolution.allTilableOpsCaptured<mlir::FunctionOpInterface>();
- }
- trailingCapture = &trailing;
-}
-
-void transform_ext::makeConvolutionMatcher(
- transform_ext::MatcherContext &context,
- StructuredOpMatcher *&convolutionCapture,
- MatchedConvolutionCaptures &captures, bool mustMatchEntireFunc) {
- StructuredOpMatcher *fill;
- StructuredOpMatcher *trailing;
- makeConvolutionMatcher(context, convolutionCapture, fill, trailing, captures,
- mustMatchEntireFunc);
-}
-
-void transform_ext::makePadMatcher(MatcherContext &context,
- CapturingOpMatcher *&padCapture,
- MatchedPadCaptures &captures,
- bool mustMatchEntireFunc) {
- auto &value = transform_ext::m_ShapedValue(context);
- value.rank(transform_ext::CaptureRank(captures.rank))
- .dim(transform_ext::AllDims(), transform_ext::CaptureDims(captures.dims))
- .elementType(CaptureElementType(captures.elementType));
- auto &opMatcher = transform_ext::m_tensorPad(context)
- .result(0, value)
- .low(AllDims(), 0)
- .yieldsExternalValue();
- if (mustMatchEntireFunc) {
- opMatcher = opMatcher.allTilableOpsCaptured<mlir::FunctionOpInterface>();
- }
- padCapture = &opMatcher;
-}
diff --git a/llvm-external-projects/iree-dialects/python/CMakeLists.txt b/llvm-external-projects/iree-dialects/python/CMakeLists.txt
index 0fc3506..488e512 100644
--- a/llvm-external-projects/iree-dialects/python/CMakeLists.txt
+++ b/llvm-external-projects/iree-dialects/python/CMakeLists.txt
@@ -15,16 +15,6 @@
ADD_TO_PARENT IREEDialectsPythonSources
)
-declare_mlir_dialect_extension_python_bindings(
- ADD_TO_PARENT IREEDialectsPythonSources.Dialects
- ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/iree/compiler"
- TD_FILE dialects/IreeStructuredTransformOps.td
- SOURCES
- dialects/transform/iree_structured.py
- dialects/_iree_structured_transform_ops_ext.py
- DIALECT_NAME transform
- EXTENSION_NAME iree_structured_transform)
-
################################################################################
# Extensions
################################################################################
@@ -36,7 +26,7 @@
SOURCES
IREEDialectsModule.cpp
EMBED_CAPI_LINK_LIBS
- IREEDialectsCAPI
+ MLIRCAPITransformDialect
PRIVATE_LINK_LIBS
LLVMSupport
)
diff --git a/llvm-external-projects/iree-dialects/python/IREEDialectsModule.cpp b/llvm-external-projects/iree-dialects/python/IREEDialectsModule.cpp
index d6bab61..10a50f8 100644
--- a/llvm-external-projects/iree-dialects/python/IREEDialectsModule.cpp
+++ b/llvm-external-projects/iree-dialects/python/IREEDialectsModule.cpp
@@ -4,10 +4,10 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "iree-dialects-c/Dialects.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/BuiltinTypes.h"
#include "mlir-c/Diagnostics.h"
+#include "mlir-c/Dialect/Transform.h"
#include "mlir-c/RegisterEverything.h"
#include "mlir/Bindings/Python/NanobindAdaptors.h"
@@ -30,7 +30,6 @@
[](MlirContext context, bool load) {
MlirDialectHandle handle = mlirGetDialectHandle__transform__();
mlirDialectHandleRegisterDialect(handle, context);
- ireeRegisterTransformExtensions(context);
if (load) {
mlirDialectHandleLoadDialect(handle, context);
}
diff --git a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/IreeStructuredTransformOps.td b/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/IreeStructuredTransformOps.td
deleted file mode 100644
index 0a10cd3..0000000
--- a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/IreeStructuredTransformOps.td
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021 The IREE Authors
-//
-// Licensed 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 PYTHON_BINDINGS_IREE_TRANSFORMEXT_BINDING
-#define PYTHON_BINDINGS_IREE_TRANSFORMEXT_BINDING
-
-include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.td"
-
-#endif // PYTHON_BINDINGS_IREE_TRANSFORMEXT_BINDING
diff --git a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/_iree_structured_transform_ops_ext.py b/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/_iree_structured_transform_ops_ext.py
deleted file mode 100644
index f1f8955..0000000
--- a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/_iree_structured_transform_ops_ext.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright 2021 The IREE Authors
-#
-# Licensed 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
-# Disable PyType, it does not seem to like the specialization pattern used in
-# MLIR.
-# pytype: skip-file
-try:
- from ..ir import *
- from ..dialects import pdl
- from ._ods_common import (
- extend_opview_class as _ods_extend_opview_class,
- segmented_accessor as _ods_segmented_accessor,
- equally_sized_accessor as _ods_equally_sized_accessor,
- get_default_loc_context as _ods_get_default_loc_context,
- get_op_result_or_value as _get_op_result_or_value,
- get_op_results_or_values as _get_op_results_or_values,
- )
- from typing import Optional, overload, Sequence, Union
-except ImportError as e:
- raise RuntimeError("Error loading imports from extension module") from e
-BoolArg = Optional[Union[bool, BoolAttr]]
-IntListArg = Optional[Union[Sequence[int], ArrayAttr]]
-StringArg = Optional[Union[str, StringAttr]]
-
-
-def _defaulted_ensure(f):
- def inner(value, default=None):
- assert value is not None or default is not None
- return f(default if value is None else value)
-
- return inner
-
-
-@_defaulted_ensure
-def _ensure_int_array_attr(value: IntListArg):
- i64 = IntegerType.get_signless(64)
- if isinstance(value, Sequence):
- return ArrayAttr.get([IntegerAttr.get(i64, i) for i in value])
- return value
-
-
-@_defaulted_ensure
-def _ensure_bool_attr(value: BoolArg):
- if isinstance(value, bool):
- return BoolAttr.get(value)
- return value
-
-
-@_defaulted_ensure
-def _ensure_string_attr(value: StringArg):
- if isinstance(value, str):
- return StringAttr.get(value)
- return value
-
-
-class LowerToLLVMOp:
- """Specialization for the LowerToLLVMOp class."""
-
- def __init__(
- self,
- *,
- reassociate_fp_reductions: BoolArg = None,
- enable_index_optimizations: BoolArg = None,
- enable_arm_neon: BoolArg = None,
- enable_arm_sve: BoolArg = None,
- enable_amx: BoolArg = None,
- enable_x86vector: BoolArg = None,
- enable_async: BoolArg = None,
- loc=None,
- ip=None
- ):
- super().__init__(
- _ensure_bool_attr(reassociate_fp_reductions, False),
- _ensure_bool_attr(enable_index_optimizations, False),
- _ensure_bool_attr(enable_arm_neon, False),
- _ensure_bool_attr(enable_arm_sve, False),
- _ensure_bool_attr(enable_amx, False),
- _ensure_bool_attr(enable_x86vector, False),
- _ensure_bool_attr(enable_async, False),
- loc=loc,
- ip=ip,
- )
diff --git a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/transform/iree_structured.py b/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/transform/iree_structured.py
deleted file mode 100644
index 563e20b..0000000
--- a/llvm-external-projects/iree-dialects/python/iree/compiler/dialects/transform/iree_structured.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright 2022 The IREE Authors
-#
-# Licensed 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
-
-from .._iree_structured_transform_ops_gen import *
diff --git a/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/CMakeLists.txt b/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/CMakeLists.txt
index 669a616..7d699b5 100644
--- a/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/CMakeLists.txt
+++ b/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/CMakeLists.txt
@@ -1,6 +1,4 @@
set(LIBS
- # Local dialects.
- IREELinalgTransformDialect
# Core dialects.
MLIRAffineDialect
MLIRArithDialect
diff --git a/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/iree-dialects-opt.cpp b/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/iree-dialects-opt.cpp
index b4a100c..2824d30 100644
--- a/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/iree-dialects-opt.cpp
+++ b/llvm-external-projects/iree-dialects/tools/iree-dialects-opt/iree-dialects-opt.cpp
@@ -4,7 +4,6 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "iree-dialects/Dialect/LinalgTransform/StructuredTransformOpsExt.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Async/IR/Async.h"
@@ -71,7 +70,6 @@
mlir::LLVM::registerInlinerInterface(registry);
mlir::linalg::registerTilingInterfaceExternalModels(registry);
- registry.addExtensions<transform_ext::StructuredTransformOpsExtension>();
mlir::bufferization::registerTransformDialectExtension(registry);
mlir::linalg::registerTransformDialectExtension(registry);
mlir::scf::registerTransformDialectExtension(registry);