[Mlir-commits] [mlir] [MLIR][Mem2Reg] Extract shared utilities for PromotableRegionOpInterface (PR #188514)
Berke Ates
llvmlistbot at llvm.org
Fri Mar 27 06:12:17 PDT 2026
https://github.com/Berke-Ates updated https://github.com/llvm/llvm-project/pull/188514
>From a3da4c14fdd68dc442c50784d677822b7dbfb29c Mon Sep 17 00:00:00 2001
From: Berke-Ates <berke at ates.ch>
Date: Wed, 25 Mar 2026 16:21:05 +0100
Subject: [PATCH] [MLIR][Mem2Reg] Extract shared utilities for
PromotableRegionOpInterface
The PromotableRegionOpInterface implementations use two helpers that are
likely useful for other dialects implementing this interface as well.
This extracts them into a common utility header so that downstream
dialects can reuse them directly.
---
.../mlir/Interfaces/Utils/MemorySlotUtils.h | 36 ++++
mlir/lib/Dialect/SCF/IR/CMakeLists.txt | 1 +
mlir/lib/Dialect/SCF/IR/MemorySlot.cpp | 84 ++------
mlir/lib/Interfaces/Utils/CMakeLists.txt | 15 ++
mlir/lib/Interfaces/Utils/MemorySlotUtils.cpp | 51 +++++
mlir/unittests/Interfaces/CMakeLists.txt | 7 +
.../Interfaces/MemorySlotUtilsTest.cpp | 188 ++++++++++++++++++
7 files changed, 319 insertions(+), 63 deletions(-)
create mode 100644 mlir/include/mlir/Interfaces/Utils/MemorySlotUtils.h
create mode 100644 mlir/lib/Interfaces/Utils/MemorySlotUtils.cpp
create mode 100644 mlir/unittests/Interfaces/MemorySlotUtilsTest.cpp
diff --git a/mlir/include/mlir/Interfaces/Utils/MemorySlotUtils.h b/mlir/include/mlir/Interfaces/Utils/MemorySlotUtils.h
new file mode 100644
index 0000000000000..66be79b5ad285
--- /dev/null
+++ b/mlir/include/mlir/Interfaces/Utils/MemorySlotUtils.h
@@ -0,0 +1,36 @@
+//===- MemorySlotUtils.h - Utilities for MemorySlot interfaces --*- 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 declares common utilities for implementing MemorySlot interfaces,
+// in particular PromotableRegionOpInterface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_INTERFACES_UTILS_MEMORYSLOTUTILS_H
+#define MLIR_INTERFACES_UTILS_MEMORYSLOTUTILS_H
+
+#include "mlir/IR/PatternMatch.h"
+
+namespace mlir {
+namespace memoryslot {
+
+/// Appends the reaching definition for the given block as an operand to its
+/// terminator. If the block has no entry in `reachingAtBlockEnd` (e.g. dead
+/// code or the region does not use the slot), `defaultReachingDef` is used.
+void updateTerminator(Block *block, Value defaultReachingDef,
+ const DenseMap<Block *, Value> &reachingAtBlockEnd);
+
+/// Creates a shallow copy of an operation with new result types, moving the
+/// regions out of the original operation and deleting the original operation.
+Operation *replaceWithNewResults(RewriterBase &rewriter, Operation *op,
+ TypeRange resultTypes);
+
+} // namespace memoryslot
+} // namespace mlir
+
+#endif // MLIR_INTERFACES_UTILS_MEMORYSLOTUTILS_H
diff --git a/mlir/lib/Dialect/SCF/IR/CMakeLists.txt b/mlir/lib/Dialect/SCF/IR/CMakeLists.txt
index fca28c5209e2d..5e7d10e4a9d6a 100644
--- a/mlir/lib/Dialect/SCF/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/SCF/IR/CMakeLists.txt
@@ -17,6 +17,7 @@ add_mlir_dialect_library(MLIRSCFDialect
MLIRFunctionInterfaces
MLIRIR
MLIRLoopLikeInterface
+ MLIRMemorySlotUtils
MLIRSideEffectInterfaces
MLIRTensorDialect
MLIRValueBoundsOpInterface
diff --git a/mlir/lib/Dialect/SCF/IR/MemorySlot.cpp b/mlir/lib/Dialect/SCF/IR/MemorySlot.cpp
index 3d61476df6014..92fc3452d4629 100644
--- a/mlir/lib/Dialect/SCF/IR/MemorySlot.cpp
+++ b/mlir/lib/Dialect/SCF/IR/MemorySlot.cpp
@@ -7,54 +7,11 @@
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/SCF/IR/SCF.h"
-#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
+#include "mlir/Interfaces/Utils/MemorySlotUtils.h"
using namespace mlir;
using namespace mlir::scf;
-//===----------------------------------------------------------------------===//
-// Helper functions
-//===----------------------------------------------------------------------===//
-
-/// Adds the corresponding reaching definition to the terminator of the block if
-/// the terminator is of the provided type.
-template <typename TermTy>
-static void
-updateTerminator(Block *block, Value defaultReachingDef,
- const llvm::DenseMap<Block *, Value> &reachingAtBlockEnd) {
- Operation *terminator = block->getTerminator();
- if (!isa<TermTy>(terminator))
- return;
- Value blockReachingDef = reachingAtBlockEnd.lookup(block);
- if (!blockReachingDef) {
- // Block is dead code or the region is not using the slot, so we use the
- // default provided reaching definition.
- blockReachingDef = defaultReachingDef;
- }
- terminator->insertOperands(terminator->getNumOperands(), {blockReachingDef});
-}
-
-/// Creates a shallow copy of an operation with new result types, moving the
-/// regions out of the original operation and deleting the original operation.
-static Operation *replaceWithNewResults(RewriterBase &rewriter, Operation *op,
- TypeRange resultTypes) {
- RewriterBase::InsertionGuard guard(rewriter);
- rewriter.setInsertionPoint(op);
- Operation *newOp =
- mlir::cloneWithoutRegions(rewriter, op, resultTypes, op->getOperands());
- rewriter.startOpModification(newOp);
- rewriter.startOpModification(op);
- for (unsigned int i : llvm::seq(op->getNumRegions()))
- newOp->getRegion(i).takeBody(op->getRegion(i));
- rewriter.finalizeOpModification(op);
- rewriter.finalizeOpModification(newOp);
-
- SmallVector<Value> replacementValues(newOp->getResults().drop_back());
- rewriter.replaceAllOpUsesWith(op, replacementValues);
- rewriter.eraseOp(op);
- return newOp;
-}
-
//===----------------------------------------------------------------------===//
// ExecuteRegionOp
//===----------------------------------------------------------------------===//
@@ -80,14 +37,15 @@ Value ExecuteRegionOp::finalizePromotion(
// Update the yield terminators to return the newly defined reaching
// definition.
for (Block &block : getRegion().getBlocks())
- updateTerminator<YieldOp>(&block, reachingDef, reachingAtBlockEnd);
+ if (isa<YieldOp>(block.getTerminator()))
+ memoryslot::updateTerminator(&block, reachingDef, reachingAtBlockEnd);
SmallVector<Type> resultTypes(getResultTypes());
resultTypes.push_back(slot.elemType);
IRRewriter rewriter(builder);
Operation *newOp =
- replaceWithNewResults(rewriter, getOperation(), resultTypes);
+ memoryslot::replaceWithNewResults(rewriter, getOperation(), resultTypes);
return newOp->getResults().back();
}
@@ -123,14 +81,14 @@ Value ForOp::finalizePromotion(
// Update the yield terminator to return the newly defined reaching
// definition.
- updateTerminator<YieldOp>(getBody(), reachingDef, reachingAtBlockEnd);
+ memoryslot::updateTerminator(getBody(), reachingDef, reachingAtBlockEnd);
SmallVector<Type> resultTypes(getResultTypes());
resultTypes.push_back(slot.elemType);
IRRewriter rewriter(builder);
Operation *newOp =
- replaceWithNewResults(rewriter, getOperation(), resultTypes);
+ memoryslot::replaceWithNewResults(rewriter, getOperation(), resultTypes);
return newOp->getResults().back();
}
@@ -187,11 +145,11 @@ Value IfOp::finalizePromotion(
// Update the yield terminators to return the newly defined reaching
// definition.
- updateTerminator<YieldOp>(&getThenRegion().back(), reachingDef,
- reachingAtBlockEnd);
+ memoryslot::updateTerminator(&getThenRegion().back(), reachingDef,
+ reachingAtBlockEnd);
if (getElseRegion().hasOneBlock()) {
- updateTerminator<YieldOp>(&getElseRegion().back(), reachingDef,
- reachingAtBlockEnd);
+ memoryslot::updateTerminator(&getElseRegion().back(), reachingDef,
+ reachingAtBlockEnd);
} else {
OpBuilder::InsertionGuard guard(rewriter);
rewriter.createBlock(&getElseRegion());
@@ -202,7 +160,7 @@ Value IfOp::finalizePromotion(
resultTypes.push_back(slot.elemType);
Operation *newOp =
- replaceWithNewResults(rewriter, getOperation(), resultTypes);
+ memoryslot::replaceWithNewResults(rewriter, getOperation(), resultTypes);
return newOp->getResults().back();
}
@@ -234,17 +192,17 @@ Value IndexSwitchOp::finalizePromotion(
// Update the yield terminators to return the newly defined reaching
// definition.
- updateTerminator<YieldOp>(&getDefaultRegion().back(), reachingDef,
- reachingAtBlockEnd);
+ memoryslot::updateTerminator(&getDefaultRegion().back(), reachingDef,
+ reachingAtBlockEnd);
for (Region &caseRegion : getCaseRegions())
- updateTerminator<YieldOp>(&caseRegion.back(), reachingDef,
- reachingAtBlockEnd);
+ memoryslot::updateTerminator(&caseRegion.back(), reachingDef,
+ reachingAtBlockEnd);
SmallVector<Type> resultTypes(getResultTypes());
resultTypes.push_back(slot.elemType);
Operation *newOp =
- replaceWithNewResults(rewriter, getOperation(), resultTypes);
+ memoryslot::replaceWithNewResults(rewriter, getOperation(), resultTypes);
return newOp->getResults().back();
}
@@ -339,10 +297,10 @@ Value WhileOp::finalizePromotion(
// Update the yield terminators to return the newly defined reaching
// definition.
- updateTerminator<ConditionOp>(&getBefore().back(),
- getBefore().getArguments().back(),
- reachingAtBlockEnd);
- updateTerminator<YieldOp>(
+ memoryslot::updateTerminator(&getBefore().back(),
+ getBefore().getArguments().back(),
+ reachingAtBlockEnd);
+ memoryslot::updateTerminator(
&getAfter().back(), getAfter().getArguments().back(), reachingAtBlockEnd);
SmallVector<Type> resultTypes(getResultTypes());
@@ -350,6 +308,6 @@ Value WhileOp::finalizePromotion(
IRRewriter rewriter(builder);
Operation *newOp =
- replaceWithNewResults(rewriter, getOperation(), resultTypes);
+ memoryslot::replaceWithNewResults(rewriter, getOperation(), resultTypes);
return newOp->getResults().back();
}
diff --git a/mlir/lib/Interfaces/Utils/CMakeLists.txt b/mlir/lib/Interfaces/Utils/CMakeLists.txt
index 8c45f66997427..c722fbf4ece09 100644
--- a/mlir/lib/Interfaces/Utils/CMakeLists.txt
+++ b/mlir/lib/Interfaces/Utils/CMakeLists.txt
@@ -1,3 +1,8 @@
+set(LLVM_OPTIONAL_SOURCES
+ InferIntRangeCommon.cpp
+ MemorySlotUtils.cpp
+ )
+
add_mlir_library(MLIRInferIntRangeCommon
InferIntRangeCommon.cpp
@@ -12,3 +17,13 @@ add_mlir_library(MLIRInferIntRangeCommon
MLIRInferIntRangeInterface
MLIRIR
)
+
+add_mlir_library(MLIRMemorySlotUtils
+ MemorySlotUtils.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces/Utils
+
+ LINK_LIBS PUBLIC
+ MLIRIR
+)
diff --git a/mlir/lib/Interfaces/Utils/MemorySlotUtils.cpp b/mlir/lib/Interfaces/Utils/MemorySlotUtils.cpp
new file mode 100644
index 0000000000000..c497970b8b188
--- /dev/null
+++ b/mlir/lib/Interfaces/Utils/MemorySlotUtils.cpp
@@ -0,0 +1,51 @@
+//===- MemorySlotUtils.cpp - Utilities for MemorySlot interfaces ----------===//
+//
+// 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 common utilities for implementing MemorySlot interfaces,
+// in particular PromotableRegionOpInterface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Interfaces/Utils/MemorySlotUtils.h"
+
+using namespace mlir;
+
+void mlir::memoryslot::updateTerminator(
+ Block *block, Value defaultReachingDef,
+ const DenseMap<Block *, Value> &reachingAtBlockEnd) {
+ Value blockReachingDef = reachingAtBlockEnd.lookup(block);
+ if (!blockReachingDef)
+ blockReachingDef = defaultReachingDef;
+ Operation *terminator = block->getTerminator();
+ terminator->insertOperands(terminator->getNumOperands(), {blockReachingDef});
+}
+
+Operation *mlir::memoryslot::replaceWithNewResults(RewriterBase &rewriter,
+ Operation *op,
+ TypeRange resultTypes) {
+ RewriterBase::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPoint(op);
+ OperationState state(op->getLoc(), op->getName(), op->getOperands(),
+ resultTypes, op->getAttrs());
+ state.propertiesAttr = op->getPropertiesAsAttribute();
+ unsigned numRegions = op->getNumRegions();
+ for (unsigned i = 0; i < numRegions; ++i)
+ state.addRegion();
+ Operation *newOp = rewriter.create(state);
+ rewriter.startOpModification(newOp);
+ rewriter.startOpModification(op);
+ for (unsigned i = 0; i < numRegions; ++i)
+ newOp->getRegion(i).takeBody(op->getRegion(i));
+ rewriter.finalizeOpModification(op);
+ rewriter.finalizeOpModification(newOp);
+
+ rewriter.replaceAllOpUsesWith(
+ op, newOp->getResults().take_front(op->getNumResults()));
+ rewriter.eraseOp(op);
+ return newOp;
+}
diff --git a/mlir/unittests/Interfaces/CMakeLists.txt b/mlir/unittests/Interfaces/CMakeLists.txt
index 7cb37323fcff2..193edda6bf8d8 100644
--- a/mlir/unittests/Interfaces/CMakeLists.txt
+++ b/mlir/unittests/Interfaces/CMakeLists.txt
@@ -2,9 +2,14 @@ add_mlir_unittest(MLIRInterfacesTests
ControlFlowInterfacesTest.cpp
DataLayoutInterfacesTest.cpp
InferIntRangeInterfaceTest.cpp
+ MemorySlotUtilsTest.cpp
SideEffectInterfacesTest.cpp
InferTypeOpInterfaceTest.cpp
+
+ DEPENDS
+ MLIRTestInterfaceIncGen
)
+target_include_directories(MLIRInterfacesTests PRIVATE "${MLIR_BINARY_DIR}/test/lib/Dialect/Test")
mlir_target_link_libraries(MLIRInterfacesTests
PRIVATE
@@ -15,6 +20,8 @@ mlir_target_link_libraries(MLIRInterfacesTests
MLIRFuncDialect
MLIRInferIntRangeInterface
MLIRInferTypeOpInterface
+ MLIRMemorySlotUtils
MLIRParser
MLIRSideEffectInterfaces
)
+target_link_libraries(MLIRInterfacesTests PRIVATE MLIRTestDialect)
diff --git a/mlir/unittests/Interfaces/MemorySlotUtilsTest.cpp b/mlir/unittests/Interfaces/MemorySlotUtilsTest.cpp
new file mode 100644
index 0000000000000..ae9eefbf03f7c
--- /dev/null
+++ b/mlir/unittests/Interfaces/MemorySlotUtilsTest.cpp
@@ -0,0 +1,188 @@
+//===- MemorySlotUtilsTest.cpp - MemorySlot utility tests -----------------===//
+//
+// 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/Interfaces/Utils/MemorySlotUtils.h"
+#include "../../test/lib/Dialect/Test/TestDialect.h"
+#include "../../test/lib/Dialect/Test/TestOps.h"
+#include "mlir/Parser/Parser.h"
+#include "gtest/gtest.h"
+
+using namespace mlir;
+
+static Operation *createOp(MLIRContext &ctx, StringRef name,
+ TypeRange resultTypes = {},
+ unsigned numRegions = 0) {
+ return Operation::create(UnknownLoc::get(&ctx), OperationName(name, &ctx),
+ resultTypes, /*operands=*/{}, NamedAttrList(),
+ /*properties=*/nullptr, /*successors=*/{},
+ numRegions);
+}
+
+//===----------------------------------------------------------------------===//
+// updateTerminator
+//===----------------------------------------------------------------------===//
+
+TEST(MemorySlotUtilsTest, UpdateTerminatorAppendsReachingDef) {
+ MLIRContext context;
+ context.allowUnregisteredDialects();
+ auto i32Ty = IntegerType::get(&context, 32);
+
+ Operation *outerOp = createOp(context, "foo.outer", {}, /*numRegions=*/1);
+ Block *block = new Block();
+ outerOp->getRegion(0).push_back(block);
+
+ Operation *defOp = createOp(context, "foo.def", {i32Ty});
+ block->push_back(defOp);
+ Operation *otherDefOp = createOp(context, "foo.other_def", {i32Ty});
+ block->push_back(otherDefOp);
+ Operation *terminator = createOp(context, "foo.terminator");
+ block->push_back(terminator);
+
+ DenseMap<Block *, Value> reachingAtBlockEnd;
+ reachingAtBlockEnd[block] = defOp->getResult(0);
+
+ // Pass otherDefOp as default, which should not be used since the map has an
+ // entry for this block.
+ memoryslot::updateTerminator(block, otherDefOp->getResult(0),
+ reachingAtBlockEnd);
+
+ EXPECT_EQ(terminator->getNumOperands(), 1u);
+ EXPECT_EQ(terminator->getOperand(0), defOp->getResult(0));
+
+ outerOp->destroy();
+}
+
+TEST(MemorySlotUtilsTest, UpdateTerminatorUsesDefaultForMissingBlock) {
+ MLIRContext context;
+ context.allowUnregisteredDialects();
+ auto i32Ty = IntegerType::get(&context, 32);
+
+ Operation *outerOp = createOp(context, "foo.outer", {}, /*numRegions=*/1);
+ Block *block = new Block();
+ outerOp->getRegion(0).push_back(block);
+
+ Operation *defOp = createOp(context, "foo.def", {i32Ty});
+ block->push_back(defOp);
+ Operation *otherDefOp = createOp(context, "foo.other_def", {i32Ty});
+ block->push_back(otherDefOp);
+ Operation *terminator = createOp(context, "foo.terminator");
+ block->push_back(terminator);
+
+ // Empty map: the default (defOp) should be used.
+ DenseMap<Block *, Value> reachingAtBlockEnd;
+
+ memoryslot::updateTerminator(block, defOp->getResult(0), reachingAtBlockEnd);
+
+ EXPECT_EQ(terminator->getNumOperands(), 1u);
+ EXPECT_EQ(terminator->getOperand(0), defOp->getResult(0));
+
+ outerOp->destroy();
+}
+
+//===----------------------------------------------------------------------===//
+// replaceWithNewResults
+//===----------------------------------------------------------------------===//
+
+TEST(MemorySlotUtilsTest, ReplaceWithNewResultsAddsResults) {
+ MLIRContext context;
+ context.allowUnregisteredDialects();
+ auto i32Ty = IntegerType::get(&context, 32);
+ auto i64Ty = IntegerType::get(&context, 64);
+ auto f32Ty = Float32Type::get(&context);
+
+ Operation *parent = createOp(context, "foo.parent", {}, /*numRegions=*/1);
+ Block *block = new Block();
+ parent->getRegion(0).push_back(block);
+
+ Operation *op = createOp(context, "foo.op", {i32Ty});
+ block->push_back(op);
+ Operation *terminator = createOp(context, "foo.terminator");
+ block->push_back(terminator);
+
+ // Add two new results (i64 and f32) on top of the original i32.
+ IRRewriter rewriter(&context);
+ Operation *newOp =
+ memoryslot::replaceWithNewResults(rewriter, op, {i32Ty, i64Ty, f32Ty});
+
+ EXPECT_EQ(newOp->getNumResults(), 3u);
+ EXPECT_EQ(newOp->getResult(0).getType(), i32Ty);
+ EXPECT_EQ(newOp->getResult(1).getType(), i64Ty);
+ EXPECT_EQ(newOp->getResult(2).getType(), f32Ty);
+ EXPECT_EQ(newOp->getName().getStringRef(), "foo.op");
+
+ parent->destroy();
+}
+
+TEST(MemorySlotUtilsTest, ReplaceWithNewResultsPreservesRegions) {
+ MLIRContext context;
+ context.allowUnregisteredDialects();
+ auto i32Ty = IntegerType::get(&context, 32);
+
+ Operation *parent = createOp(context, "foo.parent", {}, /*numRegions=*/1);
+ Block *block = new Block();
+ parent->getRegion(0).push_back(block);
+
+ Operation *op = createOp(context, "foo.region_op", {}, /*numRegions=*/1);
+ block->push_back(op);
+
+ Block *innerBlock = new Block();
+ op->getRegion(0).push_back(innerBlock);
+ Operation *innerOp = createOp(context, "foo.inner");
+ innerBlock->push_back(innerOp);
+
+ Operation *terminator = createOp(context, "foo.terminator");
+ block->push_back(terminator);
+
+ IRRewriter rewriter(&context);
+ Operation *newOp = memoryslot::replaceWithNewResults(rewriter, op, {i32Ty});
+
+ EXPECT_EQ(newOp->getNumRegions(), 1u);
+ EXPECT_FALSE(newOp->getRegion(0).empty());
+ Operation &movedInnerOp = newOp->getRegion(0).front().front();
+ EXPECT_EQ(movedInnerOp.getName().getStringRef(), "foo.inner");
+
+ parent->destroy();
+}
+
+TEST(MemorySlotUtilsTest, ReplaceWithNewResultsPreservesProperties) {
+ MLIRContext context;
+ context.loadDialect<test::TestDialect>();
+
+ const char *src = R"mlir(
+ "builtin.module"() ({
+ test.with_properties a = 42, b = "hello", c = "world",
+ flag = true, array = [1, 2, 3], array32 = [4, 5]
+ }) : () -> ()
+ )mlir";
+
+ auto module = parseSourceString<ModuleOp>(src, &context);
+ ASSERT_TRUE(!!module);
+
+ auto &opInModule = module->getBody()->front();
+ ASSERT_EQ(opInModule.getName().getStringRef(), "test.with_properties");
+
+ auto i32Ty = IntegerType::get(&context, 32);
+ IRRewriter rewriter(&context);
+ Operation *newOp =
+ memoryslot::replaceWithNewResults(rewriter, &opInModule, {i32Ty});
+
+ std::string newStr;
+ {
+ llvm::raw_string_ostream os(newStr);
+ newOp->print(os);
+ }
+
+ EXPECT_EQ(newOp->getNumResults(), 1u);
+ StringRef view(newStr);
+ EXPECT_TRUE(view.contains("a = 42"));
+ EXPECT_TRUE(view.contains("b = \"hello\""));
+ EXPECT_TRUE(view.contains("c = \"world\""));
+ EXPECT_TRUE(view.contains("flag = true"));
+ EXPECT_TRUE(view.contains("array<i64: 1, 2, 3>"));
+ EXPECT_TRUE(view.contains("array<i32: 4, 5>"));
+}
More information about the Mlir-commits
mailing list