Skip to content

Commit 7454098

Browse files
michaelmaitlandMichael Maitland
and
Michael Maitland
authored
[mlir][Value] Add getNumUses, hasNUses, and hasNUsesOrMore to Value (#142084)
We already have hasOneUse. Like llvm::Value we provide helper methods to query the number of uses of a Value. Add unittests for Value, because that was missing. --------- Co-authored-by: Michael Maitland <michaelmaitland@meta.com>
1 parent f5d3470 commit 7454098

File tree

8 files changed

+125
-17
lines changed

8 files changed

+125
-17
lines changed

mlir/docs/Tutorials/UnderstandingTheIRStructure.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,10 @@ results and print informations about them:
257257
llvm::outs() << " has no uses\n";
258258
continue;
259259
}
260-
if (result.hasOneUse()) {
260+
if (result.hasOneUse())
261261
llvm::outs() << " has a single use: ";
262-
} else {
263-
llvm::outs() << " has "
264-
<< std::distance(result.getUses().begin(),
265-
result.getUses().end())
266-
<< " uses:\n";
267-
}
262+
else
263+
llvm::outs() << " has " << result.getNumUses() << " uses:\n";
268264
for (Operation *userOp : result.getUsers()) {
269265
llvm::outs() << " - " << userOp->getName() << "\n";
270266
}

mlir/include/mlir/IR/Value.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,23 @@ class Value {
187187
/// Returns a range of all uses, which is useful for iterating over all uses.
188188
use_range getUses() const { return {use_begin(), use_end()}; }
189189

190+
/// This method computes the number of uses of this Value.
191+
///
192+
/// This is a linear time operation. Use hasOneUse, hasNUses, or
193+
/// hasNUsesOrMore to check for specific values.
194+
unsigned getNumUses() const;
195+
190196
/// Returns true if this value has exactly one use.
191197
bool hasOneUse() const { return impl->hasOneUse(); }
192198

199+
/// Return true if this Value has exactly n uses.
200+
bool hasNUses(unsigned n) const;
201+
202+
/// Return true if this value has n uses or more.
203+
///
204+
/// This is logically equivalent to getNumUses() >= N.
205+
bool hasNUsesOrMore(unsigned n) const;
206+
193207
/// Returns true if this value has no uses.
194208
bool use_empty() const { return impl->use_empty(); }
195209

mlir/lib/Bytecode/Reader/BytecodeReader.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,8 +1993,7 @@ LogicalResult BytecodeReader::Impl::sortUseListOrder(Value value) {
19931993
UseListOrderStorage customOrder =
19941994
valueToUseListMap.at(value.getAsOpaquePointer());
19951995
SmallVector<unsigned, 4> shuffle = std::move(customOrder.indices);
1996-
uint64_t numUses =
1997-
std::distance(value.getUses().begin(), value.getUses().end());
1996+
uint64_t numUses = value.getNumUses();
19981997

19991998
// If the encoding was a pair of indices `(src, dst)` for every permutation,
20001999
// reconstruct the shuffle vector for every use. Initialize the shuffle vector

mlir/lib/Dialect/SCF/IR/SCF.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1787,7 +1787,7 @@ struct ForallOpReplaceConstantInductionVar : public OpRewritePattern<ForallOp> {
17871787
for (auto [lb, ub, step, iv] :
17881788
llvm::zip(op.getMixedLowerBound(), op.getMixedUpperBound(),
17891789
op.getMixedStep(), op.getInductionVars())) {
1790-
if (iv.getUses().begin() == iv.getUses().end())
1790+
if (iv.hasNUses(0))
17911791
continue;
17921792
auto numIterations = constantTripCount(lb, ub, step);
17931793
if (!numIterations.has_value() || numIterations.value() != 1) {

mlir/lib/IR/Value.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ Block *Value::getParentBlock() {
5151
return llvm::cast<BlockArgument>(*this).getOwner();
5252
}
5353

54+
unsigned Value::getNumUses() const {
55+
return (unsigned)std::distance(use_begin(), use_end());
56+
}
57+
58+
bool Value::hasNUses(unsigned n) const {
59+
return hasNItems(use_begin(), use_end(), n);
60+
}
61+
62+
bool Value::hasNUsesOrMore(unsigned n) const {
63+
return hasNItemsOrMore(use_begin(), use_end(), n);
64+
}
65+
5466
//===----------------------------------------------------------------------===//
5567
// Value::UseLists
5668
//===----------------------------------------------------------------------===//

mlir/test/lib/IR/TestPrintDefUse.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,10 @@ struct TestPrintDefUsePass
4949
llvm::outs() << " has no uses\n";
5050
continue;
5151
}
52-
if (result.hasOneUse()) {
52+
if (result.hasOneUse())
5353
llvm::outs() << " has a single use: ";
54-
} else {
55-
llvm::outs() << " has "
56-
<< std::distance(result.getUses().begin(),
57-
result.getUses().end())
58-
<< " uses:\n";
59-
}
54+
else
55+
llvm::outs() << " has " << result.getNumUses() << " uses:\n";
6056
for (Operation *userOp : result.getUsers()) {
6157
llvm::outs() << " - " << userOp->getName() << "\n";
6258
}

mlir/unittests/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_mlir_unittest(MLIRIRTests
1717
TypeTest.cpp
1818
TypeAttrNamesTest.cpp
1919
OpPropertiesTest.cpp
20+
ValueTest.cpp
2021

2122
DEPENDS
2223
MLIRTestInterfaceIncGen

mlir/unittests/IR/ValueTest.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===- mlir/unittest/IR/ValueTest.cpp - Value unit tests ------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "mlir/IR/Value.h"
10+
#include "../../test/lib/Dialect/Test/TestDialect.h"
11+
#include "../../test/lib/Dialect/Test/TestOps.h"
12+
#include "mlir/IR/Builders.h"
13+
#include "mlir/IR/BuiltinTypes.h"
14+
#include "mlir/IR/OperationSupport.h"
15+
#include "gtest/gtest.h"
16+
17+
using namespace mlir;
18+
19+
static Operation *createOp(MLIRContext *context,
20+
ArrayRef<Value> operands = std::nullopt,
21+
ArrayRef<Type> resultTypes = std::nullopt,
22+
unsigned int numRegions = 0) {
23+
context->allowUnregisteredDialects();
24+
return Operation::create(
25+
UnknownLoc::get(context), OperationName("foo.bar", context), resultTypes,
26+
operands, std::nullopt, nullptr, std::nullopt, numRegions);
27+
}
28+
29+
namespace {
30+
31+
TEST(ValueTest, getNumUses) {
32+
MLIRContext context;
33+
Builder builder(&context);
34+
35+
Operation *op0 =
36+
createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
37+
38+
Value v0 = op0->getResult(0);
39+
EXPECT_EQ(v0.getNumUses(), (unsigned)0);
40+
41+
createOp(&context, {v0}, builder.getIntegerType(16));
42+
EXPECT_EQ(v0.getNumUses(), (unsigned)1);
43+
44+
createOp(&context, {v0, v0}, builder.getIntegerType(16));
45+
EXPECT_EQ(v0.getNumUses(), (unsigned)3);
46+
}
47+
48+
TEST(ValueTest, hasNUses) {
49+
MLIRContext context;
50+
Builder builder(&context);
51+
52+
Operation *op =
53+
createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
54+
Value v0 = op->getResult(0);
55+
EXPECT_TRUE(v0.hasNUses(0));
56+
EXPECT_FALSE(v0.hasNUses(1));
57+
58+
createOp(&context, {v0}, builder.getIntegerType(16));
59+
EXPECT_FALSE(v0.hasNUses(0));
60+
EXPECT_TRUE(v0.hasNUses(1));
61+
62+
createOp(&context, {v0, v0}, builder.getIntegerType(16));
63+
EXPECT_FALSE(v0.hasNUses(0));
64+
EXPECT_FALSE(v0.hasNUses(1));
65+
EXPECT_TRUE(v0.hasNUses(3));
66+
}
67+
68+
TEST(ValueTest, hasNUsesOrMore) {
69+
MLIRContext context;
70+
Builder builder(&context);
71+
72+
Operation *op =
73+
createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
74+
Value v0 = op->getResult(0);
75+
EXPECT_TRUE(v0.hasNUsesOrMore(0));
76+
EXPECT_FALSE(v0.hasNUsesOrMore(1));
77+
78+
createOp(&context, {v0}, builder.getIntegerType(16));
79+
EXPECT_TRUE(v0.hasNUsesOrMore(0));
80+
EXPECT_TRUE(v0.hasNUsesOrMore(1));
81+
EXPECT_FALSE(v0.hasNUsesOrMore(2));
82+
83+
createOp(&context, {v0, v0}, builder.getIntegerType(16));
84+
EXPECT_TRUE(v0.hasNUsesOrMore(0));
85+
EXPECT_TRUE(v0.hasNUsesOrMore(1));
86+
EXPECT_TRUE(v0.hasNUsesOrMore(3));
87+
EXPECT_FALSE(v0.hasNUsesOrMore(4));
88+
}
89+
90+
} // end anonymous namespace

0 commit comments

Comments
 (0)