Skip to content

Commit ed8d6c7

Browse files
author
Copybara Bot
committed
Move internal changes
GitOrigin-RevId: cf1aff0ad0997947ab87485cfeec4595cb0285d7
1 parent 30f9816 commit ed8d6c7

File tree

56 files changed

+5553
-334
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+5553
-334
lines changed

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/Plan/Analysis/BoundsAnalysis.h

Lines changed: 2 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -25,96 +25,13 @@
2525
#ifndef MLIR_TENSORRT_DIALECT_PLAN_ANALYSIS_BOUNDSANALYSIS
2626
#define MLIR_TENSORRT_DIALECT_PLAN_ANALYSIS_BOUNDSANALYSIS
2727

28+
#include "mlir-tensorrt/Interfaces/InferTensorValueRangeInterface.h"
2829
#include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
2930
#include "mlir/Analysis/DataFlow/SparseAnalysis.h"
30-
#include "mlir/Interfaces/InferIntRangeInterface.h"
31-
#include "llvm/Support/raw_ostream.h"
3231

3332
namespace mlir::plan {
3433

35-
//===----------------------------------------------------------------------===//
36-
// BoundsArray
37-
//===----------------------------------------------------------------------===//
38-
39-
/// A BoundsArray is simply an array of ConstantIntRanges used to represent
40-
/// either the bounds on a shape of a tensor-typed SSA value or the bounds
41-
/// of the element values of a statically shaped integer tensor-typed SSA value.
42-
/// When it is used to represent the bounds for the value of a tensor, we use
43-
/// a canonical packed generalized row-major layout mapping from tensor
44-
/// coordinates to storage index.
45-
class BoundsArray {
46-
public:
47-
BoundsArray(
48-
std::optional<SmallVector<ConstantIntRanges>> value = std::nullopt)
49-
: value(std::move(value)) {}
50-
51-
bool isUninitialized() const { return !value.has_value(); }
52-
53-
bool operator==(const BoundsArray &rhs) const { return value == rhs.value; }
54-
55-
ArrayRef<ConstantIntRanges> getValue() const {
56-
assert(!isUninitialized());
57-
return *value;
58-
}
59-
60-
/// Return the most conservative integer scalar bounds for an dynamic/unknown
61-
/// dimension extent.
62-
static ConstantIntRanges getMaxDimRange();
63-
64-
/// Create a BoundsValue from the min/max bounds of shape. Using this method
65-
/// ensures that the `value` are created with the correct storage bitwidth
66-
/// (an implementation detail of the analysis).
67-
static BoundsArray fromShapeBounds(ArrayRef<int64_t> min,
68-
ArrayRef<int64_t> max);
69-
70-
/// Create a `BoundsValue` using the given scalar values encoded as int64_t
71-
/// values. However, when storing the bounds, use the given bitwidth.
72-
/// TODO: remove this when we migrate away from using
73-
/// `#tensorrt.shape_profile` for value bounds.
74-
static BoundsArray fromIntegerValueBounds(unsigned bitwidth,
75-
ArrayRef<int64_t> min,
76-
ArrayRef<int64_t> max);
77-
static BoundsArray fromIntegerValueBounds(ArrayRef<llvm::APInt> min,
78-
ArrayRef<llvm::APInt> max);
79-
80-
/// For the given tensor-typed value, return the most conservative bounds for
81-
/// the shape of `v`. For each unknown dimension of the shape of `v` the
82-
/// `getMaxDimRange()` bound is used.
83-
static BoundsArray getMaxRangeForShapeBounds(Value v);
84-
85-
/// For the given statically shaped integer tensor-typed value, return the
86-
/// most conservative bounds for the value of `v`.
87-
static BoundsArray getMaxRangeForValueBounds(Value v);
88-
89-
/// For the given DenseIntElementsAttr, return a corresponding BoudnsValue
90-
/// representing constant bounds as indicated by the attribute.
91-
static BoundsArray getFromConstantValue(DenseIntElementsAttr attr);
92-
93-
/// Join two BoundsValues by performing a pointwise union of the integer
94-
/// scalar a ranges.
95-
static BoundsArray join(const BoundsArray &lhs, const BoundsArray &rhs);
96-
97-
/// Meet two BoundsValues by performing a pointwise intersection of the
98-
/// integer scalar a ranges.
99-
static BoundsArray meet(const BoundsArray &lhs, const BoundsArray &rhs);
100-
101-
/// Print a human-readable representation of the bounds.
102-
void print(raw_ostream &os) const;
103-
104-
/// Return the min/max bounds representation as two DenseElementsAttrs.
105-
std::pair<DenseElementsAttr, DenseElementsAttr>
106-
getAsElementsAttr(RankedTensorType type) const;
107-
108-
/// Returns DenseElementsAttr representation if the element ranges are all
109-
/// constant (single-value) ranges, otherwise nullopt.
110-
std::optional<DenseElementsAttr>
111-
getConstantValues(RankedTensorType type) const;
112-
113-
private:
114-
std::optional<SmallVector<ConstantIntRanges>> value;
115-
};
116-
117-
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const BoundsArray &v);
34+
using BoundsArray = mlirtrt::compiler::BoundsArray;
11835

11936
//===----------------------------------------------------------------------===//
12037
// Shape Bounds Analyses

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/Plan/IR/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ add_public_tablegen_target(MLIRTensorRTPlanDialectAttributesIncGen)
1717
set(LLVM_TARGET_DEFINITIONS PlanInterfaces.td)
1818
mlir_tablegen(PlanAttrInterfaces.h.inc -gen-attr-interface-decls)
1919
mlir_tablegen(PlanAttrInterfaces.cpp.inc -gen-attr-interface-defs)
20+
mlir_tablegen(PlanOpInterfaces.h.inc -gen-op-interface-decls)
21+
mlir_tablegen(PlanOpInterfaces.cpp.inc -gen-op-interface-defs)
2022
add_public_tablegen_target(MLIRTensorRTPlanDialectAttrInterfacesIncGen)

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/Plan/IR/Plan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "mlir-tensorrt-dialect/Interface/TensorKindOpInterface.h"
2828
#include "mlir-tensorrt/Compiler/Extension.h"
2929
#include "mlir-tensorrt/Dialect/Plan/IR/PlanInterfaces.h"
30+
#include "mlir-tensorrt/Interfaces/InferTensorValueRangeInterface.h"
3031
#include "mlir/Bytecode/BytecodeOpInterface.h"
3132
#include "mlir/IR/BuiltinAttributes.h"
3233
#include "mlir/IR/BuiltinOps.h"

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/Plan/IR/PlanOps.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
88
include "mlir/Interfaces/ControlFlowInterfaces.td"
99
include "mlir/Interfaces/DestinationStyleOpInterface.td"
1010
include "mlir/Interfaces/InferTypeOpInterface.td"
11+
include "mlir-tensorrt/Interfaces/InferTensorValueRangeInterface.td"
1112
include "mlir/IR/OpAsmInterface.td"
1213

1314
class Plan_NativeOpTrait<string name,
@@ -433,6 +434,8 @@ def Plan_WithShapeOp : Plan_Op<"with_shape",
433434
def Plan_WithValuesOp : Plan_Op<"with_values",
434435
[Pure,
435436
DeclareOpInterfaceMethods<TensorKindOpInterface>,
437+
DeclareOpInterfaceMethods<InferTensorValueRangeInterface,
438+
["inferResultRangesFromOptional"]>,
436439
AllTypesMatch<["operand", "result"]>]> {
437440
let summary =
438441
"Ties a tensor value with index SSA values representing its element values";

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/Plan/Transforms/Passes.td

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ def ClusteringPass : Pass<"plan-clustering", "::mlir::ModuleOp"> {
258258
operations will be compiled.
259259

260260
The kinds of clusters that can be formed and the specific rules for
261-
clustering are defined by the clustering configuration specified
261+
clustering are defined by the clustering configuration specified
262262
by the module's `plan.cluster_kinds` attribute. This is an array of
263-
attributes which all implement the
263+
attributes which all implement the
264264
[ClusterKindAttrInterface](../IR/PlanInterfaces.td).
265265
}];
266266

@@ -585,5 +585,35 @@ def PlanOwnershipBasedBufferDeallocationPass : Pass<
585585
];
586586
}
587587

588+
//===----------------------------------------------------------------------===//
589+
// PlanOutlineConstantFoldableSubgraphs
590+
//===----------------------------------------------------------------------===//
591+
592+
def PlanOutlineConstantFoldableSubgraphsPass : Pass<
593+
"plan-outline-constant-foldable-subgraphs",
594+
"::mlir::ModuleOp"> {
595+
let summary = "Analyze and outline constant foldable subgraphs";
596+
597+
let description = [{
598+
This pass implements forward dataflow analysis (named `SparseConstantFoldabilityAnalysis`)
599+
to find out constant foldable ops. This analysis, unlike upstream
600+
`ConstantPropagationAnalysis` is very simple and works only for pure ops.
601+
If all operands of an operation are constant foldable, all results are marked
602+
as constant foldable.
603+
Constant foldability analysis is then used along with clustering to
604+
find constant foldable subgraphs. These constant foldable subgraphs are
605+
finally outlined to a private function with `plan.constant_foldable` attribute.
606+
}];
607+
608+
let options = [
609+
Option<"skipClustering", "skip-clustering",
610+
"std::function<bool(Operation*)>", /*default=*/"nullptr",
611+
"This option enables user to extend default pass behavior and skip "
612+
"more ops from clustering. If this method returns true, `op` is not "
613+
"clustered. When op is not clustered, it is not outlined for constant "
614+
"folding. This is helpful in avoiding clustering of ops that can't be "
615+
"run e2e at compile time, in the workflow of user's choice.">,
616+
];
617+
}
588618

589619
#endif // MLIR_TENSORRT_DIALECT_PLAN_TRANSFORMS_PASSES_TD

mlir-tensorrt/compiler/include/mlir-tensorrt/Dialect/StablehloExt/IR/StableHloExt.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ void registerTensorKindOpInterfaceExternalModels(DialectRegistry &registry);
3434
/// Register StableHlo op implementations for ReifyRankedShapedTypeOpInterface.
3535
void registerTypeInferenceExternalModels(DialectRegistry &registry);
3636

37+
/// Register StableHlo op implementations for InferTensorValueRangeInterface.
38+
void registerInferTensorValueRangeInterfaceExternalModels(
39+
DialectRegistry &registry);
40+
3741
} // namespace mlir::stablehlo
3842

3943
#endif // MLIR_TENSORRT_DIALECT_STABLEHLOEXT_IR_STABLEHLOEXT_H

mlir-tensorrt/compiler/include/mlir-tensorrt/InitAllDialects.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ inline void registerAllDialects(mlir::DialectRegistry &registry) {
189189
mlir::vector::registerValueBoundsOpInterfaceExternalModels(registry);
190190

191191
IF_MLIR_TRT_ENABLE_HLO({
192+
mlir::stablehlo::registerInferTensorValueRangeInterfaceExternalModels(
193+
registry);
192194
mlir::stablehlo::registerTensorKindOpInterfaceExternalModels(registry);
193195
mlir::stablehlo::registerTypeInferenceExternalModels(registry);
194196
});
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//===- InferTensorValueRangeInterface.h --------------------------*- C++
2+
//-*-===//
3+
//
4+
// SPDX-FileCopyrightText: Copyright 2025 NVIDIA CORPORATION & AFFILIATES.
5+
// All rights reserved.
6+
// SPDX-License-Identifier: Apache-2.0
7+
//
8+
// Licensed under the Apache License, Version 2.0 (the "License");
9+
// you may not use this file except in compliance with the License.
10+
// You may obtain a copy of the License at
11+
//
12+
// http://www.apache.org/licenses/LICENSE-2.0
13+
//
14+
// Unless required by applicable law or agreed to in writing, software
15+
// distributed under the License is distributed on an "AS IS" BASIS,
16+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
// See the License for the specific language governing permissions and
18+
// limitations under the License.
19+
//
20+
//===----------------------------------------------------------------------===//
21+
///
22+
/// Declarations for InferTensorValueRangeInterface.
23+
///
24+
//===----------------------------------------------------------------------===//
25+
#ifndef MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE
26+
#define MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE
27+
28+
#include "mlir/Interfaces/InferIntRangeInterface.h"
29+
#include <optional>
30+
31+
namespace mlirtrt::compiler {
32+
33+
//===----------------------------------------------------------------------===//
34+
// BoundsArray
35+
//===----------------------------------------------------------------------===//
36+
37+
/// A BoundsArray is simply an array of mlir::ConstantIntRanges used to
38+
/// represent either the bounds on a shape of a tensor-typed SSA value or the
39+
/// bounds of the element values of a statically shaped integer tensor-typed SSA
40+
/// value. When it is used to represent the bounds for the value of a tensor, we
41+
/// use a canonical packed generalized row-major layout mapping from tensor
42+
/// coordinates to storage index.
43+
class BoundsArray {
44+
public:
45+
BoundsArray() : value(std::nullopt) {}
46+
47+
BoundsArray(llvm::ArrayRef<mlir::ConstantIntRanges> value)
48+
: value(std::make_optional(llvm::to_vector(value))) {}
49+
50+
bool isUninitialized() const { return !value.has_value(); }
51+
52+
bool operator==(const BoundsArray &rhs) const { return value == rhs.value; }
53+
54+
llvm::ArrayRef<mlir::ConstantIntRanges> getValue() const {
55+
assert(!isUninitialized());
56+
return *value;
57+
}
58+
59+
/// Return the most conservative integer scalar bounds for an dynamic/unknown
60+
/// dimension extent.
61+
static mlir::ConstantIntRanges getMaxDimRange();
62+
63+
/// Create a BoundsValue from the min/max bounds of shape. Using this method
64+
/// ensures that the `value` are created with the correct storage bitwidth
65+
/// (an implementation detail of the analysis).
66+
static BoundsArray fromShapeBounds(llvm::ArrayRef<int64_t> min,
67+
llvm::ArrayRef<int64_t> max);
68+
69+
/// Create a `BoundsValue` using the given scalar values encoded as int64_t
70+
/// values. However, when storing the bounds, use the given bitwidth.
71+
/// TODO: remove this when we migrate away from using
72+
/// `#tensorrt.shape_profile` for value bounds.
73+
static BoundsArray fromIntegerValueBounds(unsigned bitwidth,
74+
llvm::ArrayRef<int64_t> min,
75+
llvm::ArrayRef<int64_t> max);
76+
static BoundsArray fromIntegerValueBounds(llvm::ArrayRef<llvm::APInt> min,
77+
llvm::ArrayRef<llvm::APInt> max);
78+
79+
/// For the given tensor-typed value, return the most conservative bounds for
80+
/// the shape of `v`. For each unknown dimension of the shape of `v` the
81+
/// `getMaxDimRange()` bound is used.
82+
static BoundsArray getMaxRangeForShapeBounds(mlir::Value v);
83+
84+
/// For the given statically shaped integer tensor-typed value, return the
85+
/// most conservative bounds for the value of `v`.
86+
static BoundsArray getMaxRangeForValueBounds(mlir::Value v);
87+
88+
/// For the given DenseIntElementsAttr, return a corresponding BoudnsValue
89+
/// representing constant bounds as indicated by the attribute.
90+
static BoundsArray getFromConstantValue(mlir::DenseIntElementsAttr attr);
91+
92+
/// Join two BoundsValues by performing a pointwise union of the integer
93+
/// scalar a ranges.
94+
static BoundsArray join(const BoundsArray &lhs, const BoundsArray &rhs);
95+
96+
/// Meet two BoundsValues by performing a pointwise intersection of the
97+
/// integer scalar a ranges.
98+
static BoundsArray meet(const BoundsArray &lhs, const BoundsArray &rhs);
99+
100+
/// Print a human-readable representation of the bounds.
101+
void print(llvm::raw_ostream &os) const;
102+
103+
/// Return the min/max bounds representation as two DenseElementsAttrs.
104+
std::pair<mlir::DenseElementsAttr, mlir::DenseElementsAttr>
105+
getAsElementsAttr(mlir::RankedTensorType type) const;
106+
107+
/// Returns DenseElementsAttr representation if the element ranges are all
108+
/// constant (single-value) ranges, otherwise nullopt.
109+
std::optional<mlir::DenseElementsAttr>
110+
getConstantValues(mlir::RankedTensorType type) const;
111+
112+
/// The maximum allowed volume of a tensor that we allow tracking the value
113+
/// of. This is used to avoid edge cases where tracking the bounds would
114+
/// require an excess amount of memory.
115+
static constexpr int64_t kMaxVolumeThreshold = 32;
116+
117+
/// Whether the analysis should consider a value. To consider
118+
/// a value, it must be a ranked tensor of static shape and signless-or-index
119+
/// integer element type and have a total volume <= kMaxVolumeThreshold.
120+
static bool shouldAnalyzeValueBounds(mlir::Type type);
121+
122+
/// Whether the analysis should consider a value. To consider
123+
/// a value, it must be a ranked tensor of static shape and signless-or-index
124+
/// integer element type and have a total volume <= kMaxVolumeThreshold.
125+
static bool shouldAnalyzeValueBounds(mlir::Value value);
126+
127+
private:
128+
std::optional<llvm::SmallVector<mlir::ConstantIntRanges>> value;
129+
};
130+
131+
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const BoundsArray &v);
132+
133+
/// Represents either a BoundsArray lattice or a InterValueRange lattice.
134+
struct IntOrTensorValueRange
135+
: public llvm::PointerUnion<const BoundsArray *,
136+
const mlir::IntegerValueRange *> {
137+
using PointerUnion::PointerUnion;
138+
};
139+
140+
/// Similar to SetIntRangeFn, but operating on IntegerValueRange lattice values.
141+
/// This is the `setResultRanges` callback for the BoundsArray based
142+
/// interface method.
143+
using SetTensorValueLatticeFn =
144+
llvm::function_ref<void(mlir::Value, BoundsArray)>;
145+
146+
class InferTensorValueRangeInterface;
147+
148+
namespace detail {} // namespace detail
149+
150+
} // namespace mlirtrt::compiler
151+
152+
#include "mlir-tensorrt/Interfaces/InferTensorValueRangeInterface.h.inc"
153+
154+
#endif // MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE
2+
#define MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE
3+
4+
include "mlir/IR/OpBase.td"
5+
6+
//===----------------------------------------------------------------------===//
7+
// InferTensorValueRangeInterface
8+
//===----------------------------------------------------------------------===//
9+
10+
def InferTensorValueRangeInterface : OpInterface<"InferTensorValueRangeInterface"> {
11+
let description = [{
12+
Allows operations to participate in range analysis for tensor values by
13+
providing a methods that allows them to specify lower and upper bounds on their
14+
result(s) given lower and upper bounds on their input(s) if known.
15+
}];
16+
let cppNamespace = "::mlirtrt::compiler";
17+
18+
let methods = [
19+
InterfaceMethod<[{
20+
Infer the bounds on the results of this op given the lattice representation
21+
of the bounds for its arguments. For each result value or block argument
22+
(that isn't a branch argument, since the dataflow analysis handles
23+
those case), the method should call `setValueRange` with that `Value`
24+
as an argument. When implemented, `setValueRange` should be called on
25+
all result values for the operation.
26+
27+
This method allows for more precise implementations when operations
28+
want to reason about inputs which may be undefined during the analysis.
29+
}],
30+
/*retTy=*/"void",
31+
/*methodName=*/"inferResultRangesFromOptional",
32+
/*args=*/(ins "::llvm::ArrayRef<::mlirtrt::compiler::IntOrTensorValueRange>":$argRanges,
33+
"::mlirtrt::compiler::SetTensorValueLatticeFn":$setResultRanges),
34+
/*methodBody=*/"",
35+
/*defaultImplementation=*/[{}]>,
36+
];
37+
}
38+
39+
40+
#endif // MLIR_TENSORRT_INTERFACES_INFERTENSORVALUERANGEINTERFACE

0 commit comments

Comments
 (0)