diff --git a/mlir/compiler-course/kozlova_e_lab4/CMakeLists.txt b/mlir/compiler-course/kozlova_e_lab4/CMakeLists.txt new file mode 100644 index 0000000000000..69b955385fb14 --- /dev/null +++ b/mlir/compiler-course/kozlova_e_lab4/CMakeLists.txt @@ -0,0 +1,16 @@ +set(Title "ExamplePass") +set(Student "Kozlova_Ekaterina") +set(Group "FIIT3") +set(TARGET_NAME "${Title}_${Student}_${Group}_MLIR") + +file(GLOB_RECURSE SOURCES *.cpp *.h *.hpp) + +add_llvm_pass_plugin(${TARGET_NAME} + ${SOURCES} + DEPENDS + intrinsics_gen + MLIRBuiltinLocationAttributesIncGen + BUILDTREE_ONLY +) + +set(MLIR_TEST_DEPENDS ${TARGET_NAME} ${MLIR_TEST_DEPENDS} PARENT_SCOPE) diff --git a/mlir/compiler-course/kozlova_e_lab4/ExamplePass.cpp b/mlir/compiler-course/kozlova_e_lab4/ExamplePass.cpp new file mode 100644 index 0000000000000..62873601c75ee --- /dev/null +++ b/mlir/compiler-course/kozlova_e_lab4/ExamplePass.cpp @@ -0,0 +1,95 @@ +#include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/SCF/IR/SCF.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Tools/Plugins/PassPlugin.h" +#include "llvm/Support/raw_ostream.h" + +namespace { + +int computeRegionDepth(mlir::Region ®ion) { + int maxDepth = 0; + + for (mlir::Block &block : region) { + for (mlir::Operation &op : block.getOperations()) { + int currentDepth = 0; + + if (llvm::isa(op)) { + currentDepth = 1; + + int nestedDepth = 0; + for (mlir::Region &subRegion : op.getRegions()) { + nestedDepth = std::max(nestedDepth, computeRegionDepth(subRegion)); + } + + currentDepth += nestedDepth; + } + + maxDepth = std::max(maxDepth, currentDepth); + } + } + + return maxDepth; +} + +int getLoopDepth(mlir::Operation *loopOp) { + int nestedDepth = 0; + for (mlir::Region ®ion : loopOp->getRegions()) { + nestedDepth = std::max(nestedDepth, computeRegionDepth(region)); + } + return 1 + nestedDepth; +} + +class ExamplePass + : public mlir::PassWrapper> { +public: + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ExamplePass) + + mlir::StringRef getArgument() const override { + return "ExamplePass_Kozlova_Ekaterina_FIIT3_MLIR"; + } + + mlir::StringRef getDescription() const override { + return "Calculates the maximum nesting depth of regions"; + } + + void runOnOperation() override { + mlir::ModuleOp moduleOp = getOperation(); + + moduleOp.walk([&](mlir::func::FuncOp funcOp) { + llvm::SmallVector loopDepths; + mlir::Block &entryBlock = funcOp.getBody().front(); + for (mlir::Operation &op : entryBlock) { + if (llvm::isa( + op)) { + int depth = getLoopDepth(&op); + loopDepths.push_back(depth); + } + }; + + if (!loopDepths.empty()) { + mlir::OpBuilder builder(funcOp.getContext()); + auto depthAttr = builder.getI64ArrayAttr(loopDepths); + funcOp->setAttr("my_loop_depths", depthAttr); + } + }); + } +}; + +} // namespace + +static mlir::PassPluginLibraryInfo getFunctionCallCounterPassPluginInfo() { + return {MLIR_PLUGIN_API_VERSION, "ExamplePass", "1.0", + []() { mlir::PassRegistration(); }}; +} + +extern "C" LLVM_ATTRIBUTE_WEAK mlir::PassPluginLibraryInfo +mlirGetPassPluginInfo() { + return getFunctionCallCounterPassPluginInfo(); +} diff --git a/mlir/test/compiler-course/kozlova_e_lab4_test/test.mlir b/mlir/test/compiler-course/kozlova_e_lab4_test/test.mlir new file mode 100644 index 0000000000000..e9fa9fbdf78db --- /dev/null +++ b/mlir/test/compiler-course/kozlova_e_lab4_test/test.mlir @@ -0,0 +1,142 @@ +// RUN: mlir-opt -load-pass-plugin=%mlir_lib_dir/ExamplePass_Kozlova_Ekaterina_FIIT3_MLIR%shlibext \ +// RUN: --pass-pipeline="builtin.module(ExamplePass_Kozlova_Ekaterina_FIIT3_MLIR)" %s | FileCheck %s + +// CHECK: module { + +// CHECK-LABEL: func.func @no_iterations() { +// CHECK-NOT: my_loop_depths +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @no_iterations() { + return +} + +// CHECK-LABEL: func.func @test1() attributes {my_loop_depths = [1]} { +// CHECK-NEXT: %c0 = arith.constant 0 : index +// CHECK-NEXT: %c7 = arith.constant 7 : index +// CHECK-NEXT: %c1 = arith.constant 1 : index +// CHECK-NEXT: scf.for %arg0 = %c0 to %c7 step %c1 { +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @test1() { + %c0 = arith.constant 0 : index + %c7 = arith.constant 7 : index + %c1 = arith.constant 1 : index + scf.for %i = %c0 to %c7 step %c1 { + } + return +} + +// CHECK-LABEL: func.func @test2() attributes {my_loop_depths = [2]} { +// CHECK-NEXT: %c0 = arith.constant 0 : index +// CHECK-NEXT: %c7 = arith.constant 7 : index +// CHECK-NEXT: %c1 = arith.constant 1 : index +// CHECK-NEXT: %true = arith.constant true +// CHECK-NEXT: scf.for %arg0 = %c0 to %c7 step %c1 { +// CHECK-NEXT: scf.if %true { +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @test2() { + %c0 = arith.constant 0 : index + %c7 = arith.constant 7 : index + %c1 = arith.constant 1 : index + %cond = arith.constant true + scf.for %i = %c0 to %c7 step %c1 { + scf.if %cond { + } + } + return +} + +// CHECK-LABEL: func.func @test3() attributes {my_loop_depths = [3]} { +// CHECK-NEXT: %c0 = arith.constant 0 : index +// CHECK-NEXT: %c7 = arith.constant 7 : index +// CHECK-NEXT: %c3 = arith.constant 3 : index +// CHECK-NEXT: %true = arith.constant true +// CHECK-NEXT: scf.for %arg0 = %c0 to %c7 step %c3 { +// CHECK-NEXT: scf.if %true { +// CHECK-NEXT: scf.if %true { +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @test3() { + %c0 = arith.constant 0 : index + %c7 = arith.constant 7 : index + %c3 = arith.constant 3 : index + %cond = arith.constant true + scf.for %i = %c0 to %c7 step %c3 { + scf.if %cond { + scf.if %cond { + } + } + } + return +} + +// CHECK-LABEL: func.func @test4() attributes {my_loop_depths = [2]} { +// CHECK-NEXT: %c0 = arith.constant 0 : index +// CHECK-NEXT: %c20 = arith.constant 20 : index +// CHECK-NEXT: %c7 = arith.constant 7 : index +// CHECK-NEXT: %c1 = arith.constant 1 : index +// CHECK-NEXT: scf.for %arg0 = %c0 to %c20 step %c1 { +// CHECK-NEXT: scf.for %arg1 = %c0 to %c7 step %c1 { +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @test4() { + %c0 = arith.constant 0 : index + %c20 = arith.constant 20 : index + %c7 = arith.constant 7 : index + %c1 = arith.constant 1 : index + scf.for %i = %c0 to %c20 step %c1 { + scf.for %j = %c0 to %c7 step %c1 { + } + } + return +} + +// CHECK-LABEL: func.func @test5() attributes {my_loop_depths = [3]} { +// CHECK-NEXT: %c0 = arith.constant 0 : index +// CHECK-NEXT: %c7 = arith.constant 7 : index +// CHECK-NEXT: %c1 = arith.constant 1 : index +// CHECK-NEXT: %true = arith.constant true +// CHECK-NEXT: scf.if %true { +// CHECK-NEXT: scf.for %arg0 = %c0 to %c7 step %c1 { +// CHECK-NEXT: scf.if %true { +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } + +func.func @test5() { + %c0 = arith.constant 0 : index + %c7 = arith.constant 7 : index + %c1 = arith.constant 1 : index + %cond = arith.constant true + scf.if %cond { + scf.for %i = %c0 to %c7 step %c1 { + scf.if %cond { + } + } + } + return +} + + +// CHECK-LABEL: func.func @test6() attributes {my_loop_depths = [1]} { +// CHECK-NEXT: affine.for %arg0 = 0 to 10 { +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } +func.func @test6() { + affine.for %i = 0 to 10 { + } + return +} \ No newline at end of file