[Mlir-commits] [mlir] 1ef51e0 - [mlir][Analysis] Introduce LoopInfo in mlir
Christian Ulmann
llvmlistbot at llvm.org
Wed Apr 5 05:58:00 PDT 2023
Author: Christian Ulmann
Date: 2023-04-05T12:57:16Z
New Revision: 1ef51e0452a473f404edc635412685fce6f61004
URL: https://github.com/llvm/llvm-project/commit/1ef51e0452a473f404edc635412685fce6f61004
DIFF: https://github.com/llvm/llvm-project/commit/1ef51e0452a473f404edc635412685fce6f61004.diff
LOG: [mlir][Analysis] Introduce LoopInfo in mlir
This commit introduces an instantiation of LLVM's LoopInfo for CFGs in
MLIR. To test the LoopInfo, a test pass is added the checks the analysis
results for a set of CFGs.
Reviewed By: ftynse
Differential Revision: https://reviews.llvm.org/D147323
Added:
mlir/include/mlir/Analysis/CFGLoopInfo.h
mlir/lib/Analysis/CFGLoopInfo.cpp
mlir/test/Analysis/test-cfg-loop-info.mlir
mlir/test/lib/Analysis/TestCFGLoopInfo.cpp
Modified:
mlir/include/mlir/IR/RegionGraphTraits.h
mlir/lib/Analysis/CMakeLists.txt
mlir/test/lib/Analysis/CMakeLists.txt
mlir/tools/mlir-opt/mlir-opt.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/Analysis/CFGLoopInfo.h b/mlir/include/mlir/Analysis/CFGLoopInfo.h
new file mode 100644
index 0000000000000..4bbae77f75797
--- /dev/null
+++ b/mlir/include/mlir/Analysis/CFGLoopInfo.h
@@ -0,0 +1,43 @@
+//===- CFGLoopInfo.h - LoopInfo analysis for region bodies ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CFGLoopInfo analysis for MLIR. The CFGLoopInfo is used
+// to identify natural loops and determine the loop depth of various nodes of a
+// CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ANALYSIS_LOOPINFO_H
+#define MLIR_ANALYSIS_LOOPINFO_H
+
+#include "mlir/IR/Dominance.h"
+#include "mlir/IR/RegionGraphTraits.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/LoopInfoImpl.h"
+
+namespace mlir {
+
+/// Representation of a single loop formed by blocks. The inherited LoopBase
+/// class provides accessors to the loop analysis.
+class CFGLoop : public llvm::LoopBase<mlir::Block, mlir::CFGLoop> {
+private:
+ explicit CFGLoop(mlir::Block *block);
+
+ friend class llvm::LoopBase<mlir::Block, CFGLoop>;
+ friend class llvm::LoopInfoBase<mlir::Block, CFGLoop>;
+};
+
+/// An LLVM LoopInfo instantiation for MLIR that provides access to CFG loops
+/// found in the dominator tree.
+class CFGLoopInfo : public llvm::LoopInfoBase<mlir::Block, mlir::CFGLoop> {
+public:
+ CFGLoopInfo(const llvm::DominatorTreeBase<mlir::Block, false> &domTree);
+};
+} // namespace mlir
+
+#endif // MLIR_ANALYSIS_LOOPINFO_H
diff --git a/mlir/include/mlir/IR/RegionGraphTraits.h b/mlir/include/mlir/IR/RegionGraphTraits.h
index 498064e3c11cf..d7d80d9b35806 100644
--- a/mlir/include/mlir/IR/RegionGraphTraits.h
+++ b/mlir/include/mlir/IR/RegionGraphTraits.h
@@ -49,6 +49,40 @@ struct GraphTraits<Inverse<mlir::Block *>> {
}
};
+template <>
+struct GraphTraits<const mlir::Block *> {
+ using ChildIteratorType = mlir::Block::succ_iterator;
+ using Node = const mlir::Block;
+ using NodeRef = Node *;
+
+ static NodeRef getEntryNode(NodeRef node) { return node; }
+
+ static ChildIteratorType child_begin(NodeRef node) {
+ return const_cast<mlir::Block *>(node)->succ_begin();
+ }
+ static ChildIteratorType child_end(NodeRef node) {
+ return const_cast<mlir::Block *>(node)->succ_end();
+ }
+};
+
+template <>
+struct GraphTraits<Inverse<const mlir::Block *>> {
+ using ChildIteratorType = mlir::Block::pred_iterator;
+ using Node = const mlir::Block;
+ using NodeRef = Node *;
+
+ static NodeRef getEntryNode(Inverse<NodeRef> inverseGraph) {
+ return inverseGraph.Graph;
+ }
+
+ static ChildIteratorType child_begin(NodeRef node) {
+ return const_cast<mlir::Block *>(node)->pred_begin();
+ }
+ static ChildIteratorType child_end(NodeRef node) {
+ return const_cast<mlir::Block *>(node)->pred_end();
+ }
+};
+
template <>
struct GraphTraits<mlir::Region *> : public GraphTraits<mlir::Block *> {
using GraphType = mlir::Region *;
diff --git a/mlir/lib/Analysis/CFGLoopInfo.cpp b/mlir/lib/Analysis/CFGLoopInfo.cpp
new file mode 100644
index 0000000000000..983643f97af53
--- /dev/null
+++ b/mlir/lib/Analysis/CFGLoopInfo.cpp
@@ -0,0 +1,19 @@
+//===- CFGLoopInfo.cpp - LoopInfo analysis for region bodies --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Analysis/CFGLoopInfo.h"
+
+using namespace mlir;
+
+CFGLoop::CFGLoop(mlir::Block *block)
+ : llvm::LoopBase<mlir::Block, CFGLoop>(block) {}
+
+CFGLoopInfo::CFGLoopInfo(
+ const llvm::DominatorTreeBase<mlir::Block, false> &domTree) {
+ analyze(domTree);
+}
diff --git a/mlir/lib/Analysis/CMakeLists.txt b/mlir/lib/Analysis/CMakeLists.txt
index b68e03c5748fc..b2fbf70ecc8cf 100644
--- a/mlir/lib/Analysis/CMakeLists.txt
+++ b/mlir/lib/Analysis/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_OPTIONAL_SOURCES
DataLayoutAnalysis.cpp
FlatLinearValueConstraints.cpp
Liveness.cpp
+ CFGLoopInfo.cpp
SliceAnalysis.cpp
AliasAnalysis/LocalAliasAnalysis.cpp
@@ -24,6 +25,7 @@ add_mlir_library(MLIRAnalysis
DataLayoutAnalysis.cpp
FlatLinearValueConstraints.cpp
Liveness.cpp
+ CFGLoopInfo.cpp
SliceAnalysis.cpp
AliasAnalysis/LocalAliasAnalysis.cpp
diff --git a/mlir/test/Analysis/test-cfg-loop-info.mlir b/mlir/test/Analysis/test-cfg-loop-info.mlir
new file mode 100644
index 0000000000000..cc1a5c39b4593
--- /dev/null
+++ b/mlir/test/Analysis/test-cfg-loop-info.mlir
@@ -0,0 +1,115 @@
+// RUN: mlir-opt -pass-pipeline="builtin.module(any(test-cfg-loop-info))" --split-input-file %s 2>&1 | FileCheck %s
+
+// CHECK-LABEL: Testing : "no_loop_single_block"
+// CHECK: no loops
+func.func @no_loop_single_block() {
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "no_loop"
+// CHECK: no loops
+func.func @no_loop() {
+ cf.br ^bb1
+^bb1:
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "simple_loop"
+// CHECK-NEXT: Blocks : ^[[BB0:.*]], ^[[BB1:.*]], ^[[BB2:.*]], ^[[BB3:.*]]
+// CHECK: Loop at depth 1 containing:
+// CHECK-SAME: ^[[BB1]]<header><exiting>
+// CHECK-SAME: ^[[BB2]]<latch>
+func.func @simple_loop(%c: i1) {
+ cf.br ^bb1
+^bb1:
+ cf.cond_br %c, ^bb2, ^bb3
+^bb2:
+ cf.br ^bb1
+^bb3:
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "single_block_loop"
+// CHECK-NEXT: Blocks : ^[[BB0:.*]], ^[[BB1:.*]], ^[[BB2:.*]]
+// CHECK: Loop at depth 1 containing:
+// CHECK-SAME: ^[[BB1]]<header><latch><exiting>
+func.func @single_block_loop(%c: i1) {
+ cf.br ^bb1
+^bb1:
+ cf.cond_br %c, ^bb1, ^bb2
+^bb2:
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "nested_loop"
+// CHECK-NEXT: Blocks : ^[[BB0:.*]], ^[[BB1:.*]], ^[[BB2:.*]], ^[[BB3:.*]], ^[[BB4:.*]]
+// CHECK: Loop at depth 1
+// CHECK-SAME: ^[[BB1]]<header><exiting>
+// CHECK-SAME: ^[[BB2]]<latch>
+// CHECK-SAME: ^[[BB3]]
+// CHECK: Loop at depth 2
+// CHECK-SAME: ^[[BB2]]<header><exiting>
+// CHECK-SAME: ^[[BB3]]<latch>
+func.func @nested_loop(%c: i1) {
+ cf.br ^bb1
+^bb1:
+ cf.cond_br %c, ^bb2, ^bb4
+^bb2:
+ cf.cond_br %c, ^bb1, ^bb3
+^bb3:
+ cf.br ^bb2
+^bb4:
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "multi_latch"
+// CHECK-NEXT: Blocks : ^[[BB0:.*]], ^[[BB1:.*]], ^[[BB2:.*]], ^[[BB3:.*]], ^[[BB4:.*]]
+// CHECK: Loop at depth 1
+// CHECK-SAME: ^[[BB1]]<header><exiting>
+// CHECK-SAME: ^[[BB2]]<latch>
+// CHECK-SAME: ^[[BB3]]<latch>
+func.func @multi_latch(%c: i1) {
+ cf.br ^bb1
+^bb1:
+ cf.cond_br %c, ^bb4, ^bb2
+^bb2:
+ cf.cond_br %c, ^bb1, ^bb3
+^bb3:
+ cf.br ^bb1
+^bb4:
+ return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "multiple_loops"
+// CHECK-NEXT: Blocks : ^[[BB0:.*]], ^[[BB1:.*]], ^[[BB2:.*]], ^[[BB3:.*]], ^[[BB4:.*]], ^[[BB5:.*]]
+// CHECK: Loop at depth 1
+// CHECK-SAME: ^[[BB3]]<header><exiting>
+// CHECK-SAME: ^[[BB4]]<latch>
+// CHECK: Loop at depth 1
+// CHECK-SAME: ^[[BB1]]<header>
+// CHECK-SAME: ^[[BB2]]<latch><exiting>
+func.func @multiple_loops(%c: i1) {
+ cf.br ^bb1
+^bb1:
+ cf.br ^bb2
+^bb2:
+ cf.cond_br %c, ^bb3, ^bb1
+^bb3:
+ cf.cond_br %c, ^bb5, ^bb4
+^bb4:
+ cf.br ^bb3
+^bb5:
+ return
+}
diff --git a/mlir/test/lib/Analysis/CMakeLists.txt b/mlir/test/lib/Analysis/CMakeLists.txt
index d83a8d5c070bc..00e77e858e7f3 100644
--- a/mlir/test/lib/Analysis/CMakeLists.txt
+++ b/mlir/test/lib/Analysis/CMakeLists.txt
@@ -4,6 +4,7 @@ add_mlir_library(MLIRTestAnalysis
TestCallGraph.cpp
TestDataFlowFramework.cpp
TestLiveness.cpp
+ TestCFGLoopInfo.cpp
TestMatchReduction.cpp
TestMemRefBoundCheck.cpp
TestMemRefDependenceCheck.cpp
diff --git a/mlir/test/lib/Analysis/TestCFGLoopInfo.cpp b/mlir/test/lib/Analysis/TestCFGLoopInfo.cpp
new file mode 100644
index 0000000000000..fbba93da2cce1
--- /dev/null
+++ b/mlir/test/lib/Analysis/TestCFGLoopInfo.cpp
@@ -0,0 +1,75 @@
+//===- TestCFGLoopInfo.cpp - Test CFG loop info analysis ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements logic for testing the CFGLoopInfo analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Analysis/CFGLoopInfo.h"
+#include "mlir/IR/FunctionInterfaces.h"
+#include "mlir/Pass/Pass.h"
+
+using namespace mlir;
+
+namespace {
+/// A testing pass that applies the CFGLoopInfo analysis on a region and prints
+/// the information it collected to llvm::errs().
+struct TestCFGLoopInfo
+ : public PassWrapper<TestCFGLoopInfo, InterfacePass<FunctionOpInterface>> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCFGLoopInfo)
+
+ StringRef getArgument() const final { return "test-cfg-loop-info"; }
+ StringRef getDescription() const final {
+ return "Test the loop info analysis.";
+ }
+
+ void runOnOperation() override;
+};
+} // namespace
+
+void TestCFGLoopInfo::runOnOperation() {
+ auto func = getOperation();
+ DominanceInfo &domInfo = getAnalysis<DominanceInfo>();
+ Region ®ion = func.getFunctionBody();
+
+ // Prints the label of the test.
+ llvm::errs() << "Testing : " << func.getNameAttr() << "\n";
+ if (region.empty()) {
+ llvm::errs() << "empty region\n";
+ return;
+ }
+
+ // Print all the block identifiers first such that the tests can match them.
+ llvm::errs() << "Blocks : ";
+ region.front().printAsOperand(llvm::errs());
+ for (auto &block : region.getBlocks()) {
+ llvm::errs() << ", ";
+ block.printAsOperand(llvm::errs());
+ }
+ llvm::errs() << "\n";
+
+ if (region.getBlocks().size() == 1) {
+ llvm::errs() << "no loops\n";
+ return;
+ }
+
+ llvm::DominatorTreeBase<mlir::Block, false> &domTree =
+ domInfo.getDomTree(®ion);
+ mlir::CFGLoopInfo loopInfo(domTree);
+
+ if (loopInfo.getTopLevelLoops().empty())
+ llvm::errs() << "no loops\n";
+ else
+ loopInfo.print(llvm::errs());
+}
+
+namespace mlir {
+namespace test {
+void registerTestCFGLoopInfoPass() { PassRegistration<TestCFGLoopInfo>(); }
+} // namespace test
+} // namespace mlir
diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp
index 855c6a6e0f28a..2ddd83f36f52d 100644
--- a/mlir/tools/mlir-opt/mlir-opt.cpp
+++ b/mlir/tools/mlir-opt/mlir-opt.cpp
@@ -99,6 +99,7 @@ void registerTestLinalgGreedyFusion();
void registerTestLinalgTransforms();
void registerTestLivenessPass();
void registerTestLoopFusion();
+void registerTestCFGLoopInfoPass();
void registerTestLoopMappingPass();
void registerTestLoopUnrollingPass();
void registerTestLowerToLLVM();
@@ -211,6 +212,7 @@ void registerTestPasses() {
mlir::test::registerTestLinalgTransforms();
mlir::test::registerTestLivenessPass();
mlir::test::registerTestLoopFusion();
+ mlir::test::registerTestCFGLoopInfoPass();
mlir::test::registerTestLoopMappingPass();
mlir::test::registerTestLoopUnrollingPass();
mlir::test::registerTestLowerToLLVM();
More information about the Mlir-commits
mailing list