tvm
Loading...
Searching...
No Matches
analyzer.h
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
24#ifndef TVM_ARITH_ANALYZER_H_
25#define TVM_ARITH_ANALYZER_H_
26
27#include <tvm/arith/int_set.h>
28#include <tvm/ffi/cast.h>
29#include <tvm/ffi/reflection/registry.h>
30#include <tvm/ffi/string.h>
31#include <tvm/ir/expr.h>
32#include <tvm/ir/with_context.h>
33
34#include <limits>
35#include <memory>
36#include <unordered_map>
37#include <utility>
38#include <vector>
39
40namespace tvm {
42namespace arith {
43//-------------------------------------------------------
44// Base integer analysis API.
45//
46// We have multiple type of analyzers to do relaxed
47// integer set analysis(bound analysis, modulo) and
48// equivalence checking and simplification.
49//
50// Importantly, each analyzer may need result from
51// another analyzer.
52//-------------------------------------------------------
53
54// Forward declare the analyzer object and its reference handle.
55class AnalyzerObj;
56class Analyzer;
58
59using tirx::Var;
60
67
75enum class ProofStrength : int {
77 kDefault = 0,
82};
83
90class ConstIntBoundNode : public ffi::Object {
91 public:
94
95 static void RegisterReflection() {
96 namespace refl = tvm::ffi::reflection;
97 refl::ObjectDef<ConstIntBoundNode>()
98 .def_ro("min_value", &ConstIntBoundNode::min_value)
99 .def_ro("max_value", &ConstIntBoundNode::max_value);
100 }
101
103 static const constexpr int64_t kPosInf = std::numeric_limits<int64_t>::max();
108 static const constexpr int64_t kNegInf = -kPosInf;
109
111 TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.ConstIntBound", ConstIntBoundNode, ffi::Object);
112};
113
131
136 public:
138 std::unordered_map<PrimExpr, ConstIntBound, ffi::ObjectPtrHash, ffi::ObjectPtrEqual>;
145
153
161 TVM_DLL void Update(const Var& var, const ConstIntBound& info, bool allow_override = false);
162
170 TVM_DLL void Bind(const Var& var, const Range& range, bool allow_override = false);
171
177 TVM_DLL bool IsBound(const Var& var) const;
178
179 private:
180 friend class AnalyzerObj;
181 friend class ConstraintContext;
182 explicit ConstIntBoundAnalyzer(AnalyzerObj* parent);
184 void CopyFrom(const ConstIntBoundAnalyzer& other);
191 std::function<void()> EnterConstraint(const PrimExpr& constraint);
192 struct Entry;
193 class Impl;
195 Impl* impl_;
196};
197
210class ModularSetNode : public ffi::Object {
211 public:
216
217 static void RegisterReflection() {
218 namespace refl = tvm::ffi::reflection;
219 refl::ObjectDef<ModularSetNode>()
220 .def_ro("coeff", &ModularSetNode::coeff)
221 .def_ro("base", &ModularSetNode::base);
222 }
223
225 TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.ModularSet", ModularSetNode, ffi::Object);
226};
227
232class ModularSet : public ffi::ObjectRef {
233 public:
235
237};
238
243 public:
257 TVM_DLL void Update(const Var& var, const ModularSet& info, bool allow_override = false);
258
259 private:
260 friend class AnalyzerObj;
261 friend class ConstraintContext;
262 explicit ModularSetAnalyzer(AnalyzerObj* parent);
264 void CopyFrom(const ModularSetAnalyzer& other);
271 std::function<void()> EnterConstraint(const PrimExpr& constraint);
272 struct Entry;
273 class Impl;
275 Impl* impl_;
276};
277
282 public:
289
297 TVM_DLL void Update(const Var& var, const PrimExpr& new_expr, bool allow_override = false);
298
306 TVM_DLL std::function<void()> EnterConstraint(const PrimExpr& constraint, bool is_assume = false);
307
321 // No extensions enabled
322 kNone = 0,
323
324 /* When simplifying an inequality, attempt to use scope-based knowns.
325 *
326 * Example:
327 * if_then_else(i<j && j<k, i<k, false) => if_then_else(i<j && j<k, true, false)
328 */
330
331 /* When simplifying a boolean expression, convert to an AND of ORs
332 * (conjunctive normal form).
333 *
334 * Example:
335 * (a && b) || c => (a || c) && (b || c)
336 */
338
339 /* When simplifying a boolean AND or a boolean OR, simplify each
340 * branch under the assumption that the other branch does not
341 * already dominate the result. That is, simplify each branch of
342 * (A && B) under the assumption that the other branch is true,
343 * and simplify each branch of (A || B) under the assumption that
344 * the other branch is false.
345 *
346 * Example:
347 * (n < 10) && (n < 5) => (n < 10)
348 * (n < 10) || (n < 5) => (n < 5)
349 */
351
352 /* Special handling for expressions `(A+B)*C < (A*B)*D`
353 *
354 * Expressions of the form `(A+B)*C < (A*B)*D` can occur occur
355 * when comparing the number of operations required for two
356 * different orderings in which matrix multiplications can be
357 * performed. Proving or disproving this conditional allows an
358 * optimal order of execution to be selected, even for dynamic
359 * argument shapes.
360 *
361 * The default behavior of `ConstIntBounds` assumes that each term
362 * in an expression is independent, and is insufficient to prove
363 * these inequalities. For example, the maximum value of `(A+B)*C
364 * - (A*B)*D` is determined by taking the maximum value of
365 * `(A+B)*C` and subtracting the minimum value of `(A*B)*D`.
366 * While this algorithm can be applied in all cases, the bound it
367 * provides is looser than strictly required.
368 *
369 * This extension adds a check for this case. When `A`, `B`, `C`,
370 * and `D` are all positive values, as is the case for tensor
371 * shapes, the inequality can be written as `1/A + 1/B < D/C`. If
372 * this inequality holds for the minimum values of `A`, `B`, and
373 * `D`, along with the maximum value of `C`, then the inequality
374 * holds for all values.
375 *
376 * This extension requires little to no performance overhead, and
377 * may be enabled by default in future releases.
378 */
380 };
381
388
391
393 TVM_DLL ffi::ObjectRef GetStatsCounters() const;
394
397
413
414 private:
415 friend class AnalyzerObj;
416 friend class ConstraintContext;
418 explicit RewriteSimplifier(AnalyzerObj* parent);
420 void CopyFrom(const RewriteSimplifier& other);
421 class Impl;
423 Impl* impl_;
424};
425
430 public:
437
445 TVM_DLL void Update(const Var& var, const PrimExpr& new_expr, bool allow_override = false);
446
447 private:
448 friend class AnalyzerObj;
449 friend class ConstraintContext;
450 explicit CanonicalSimplifier(AnalyzerObj* parent);
452 void CopyFrom(const CanonicalSimplifier& other);
453 class Impl;
455 Impl* impl_;
456};
457
463enum class CompareResult : int {
464 kInconsistent = 0,
465 kEQ = 1,
466 kLT = 2,
467 kLE = 3,
468 kGT = 4,
469 kGE = 5,
470 kNE = 6,
471 kUnknown = 7
472};
473
475 return CompareResult(static_cast<int>(lhs) & static_cast<int>(rhs));
476}
478 return CompareResult(static_cast<int>(lhs) | static_cast<int>(rhs));
479}
480
488 public:
489 /* \brief Using previously specified knowns, compare the expressions provided
490 *
491 * \param lhs The left-hand side of the comparison
492 *
493 * \param rhs The right-hand side of the comparison
494 *
495 * \param propagate_inequalities If true, attempt to find a sequence
496 * of transitive inequalities that allow the lhs and rhs to be
497 * compared. If false, only use the known comparison that have been
498 * directly provided. Using `propagate_inequalities = false` is
499 * roughly equivalent to comparing against all known inequality
500 * expressions using `ExprDeepEqual`, but also allows for constant
501 * offsets on either side of the inequality.
502 *
503 * \return The most specific result that can be proven about the
504 * comparison. If nothing can be proven, returns kUnknown.
505 */
507 bool propagate_inequalities = true);
508
515 TVM_DLL void Bind(const Var& var, const PrimExpr& expr, bool allow_override = false);
516
523 TVM_DLL void Bind(const Var& var, const Range& range, bool allow_override = false);
524
532
533 private:
534 friend class AnalyzerObj;
535 friend class ConstraintContext;
538 void CopyFrom(const TransitiveComparisonAnalyzer& other);
539 class Impl;
541 std::unique_ptr<Impl> impl_;
542};
543
548 public:
557 TVM_DLL IntSet operator()(const PrimExpr& expr, const ffi::Map<Var, IntSet>& dom_map);
558
568
576 TVM_DLL void Update(const Var& var, const IntSet& new_interval_set, bool allow_override = false);
577
585 TVM_DLL void Bind(const Var& var, const Range& new_range, bool allow_override = false);
586
587 std::function<void()> EnterConstraint(const PrimExpr& constraint);
588
589 private:
590 friend class AnalyzerObj;
591 explicit IntSetAnalyzer(AnalyzerObj* parent);
593 void CopyFrom(const IntSetAnalyzer& other);
594 class Impl;
596 Impl* impl_;
597};
598
607
614
615class Z3Prover {
616 public:
624 TVM_DLL void Bind(const Var& var, const Range& new_range, bool allow_override = false);
625
633 TVM_DLL void Bind(const Var& var, const PrimExpr& expr, bool allow_override = false);
634
640 TVM_DLL bool IsEnabled() const;
641
648 TVM_DLL bool CanProve(const PrimExpr& expr);
649
657 std::function<void()> EnterConstraint(const PrimExpr& constraint, bool is_assume = false);
658
665 ffi::String GetSMTLIB2(const ffi::Optional<PrimExpr> expr);
666
672 ffi::String GetStats();
673
679 void SetTimeoutMs(unsigned timeout_ms);
680
686 void SetRLimit(unsigned rlimit);
687
694 ffi::String GetModel(const PrimExpr& expr);
695
709
710 private:
711 friend class AnalyzerObj;
712 friend class Analyzer;
713 explicit Z3Prover(AnalyzerObj* parent);
715 void CopyFrom(const Z3Prover& other);
716 class Impl;
717 Impl* impl_;
718};
719
730class TVM_DLL AnalyzerObj : public ffi::Object {
731 public:
767 void MarkGlobalNonNegValue(const PrimExpr& value);
780 void Bind(const Var& var, const PrimExpr& expr, bool allow_override = false);
793 void Bind(const Var& var, const Range& range, bool allow_override = false);
802 void Bind(const ffi::Map<Var, Range>& variables, bool allow_override = false);
838 bool CanProveEqual(const PrimExpr& lhs, const PrimExpr& rhs);
868 bool CanProve(const PrimExpr& cond, ProofStrength strength = ProofStrength::kDefault);
869
883 PrimExpr Simplify(const PrimExpr& expr, int steps = 2);
884
904
914 static constexpr bool _type_mutable = true;
915 TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.Analyzer", AnalyzerObj, ffi::Object);
916};
917
931class Analyzer : public ffi::ObjectRef {
932 public:
935 explicit Analyzer(ffi::ObjectPtr<AnalyzerObj> n) : ffi::ObjectRef(std::move(n)) {
936 TVM_FFI_ICHECK(this->get() != nullptr);
937 }
939};
940
958 private:
959 // declare friend to enable with.
960 friend class With<ConstraintContext>;
968 : ConstraintContext(analyzer, std::move(constraint), false) {}
977 : analyzer_(analyzer), constraint_(std::move(constraint)), is_assume_(is_assume) {}
986 : ConstraintContext(ffi::GetRef<Analyzer>(analyzer), std::move(constraint), false) {}
994 : ConstraintContext(ffi::GetRef<Analyzer>(analyzer), std::move(constraint), is_assume) {}
995 // enter the scope.
996 TVM_DLL void EnterWithScope();
997 // exit the scope.
998 TVM_DLL void ExitWithScope();
1000 Analyzer analyzer_;
1002 PrimExpr constraint_;
1004 std::vector<std::function<void()>> recovery_functions_;
1006 bool is_assume_;
1007};
1008
1009} // namespace arith
1010} // namespace tvm
1011#endif // TVM_ARITH_ANALYZER_H_
Typed reference/view over any Expr whose ExprNode::ty is PrimType.
Definition base_expr.h:401
Range container
Definition expr.h:610
Managed reference to VarNode.
Definition expr.h:372
RAII wrapper function to enter and exit a context object similar to python's with syntax.
Definition with_context.h:59
Analyzer that contains bunch of sub-analyzers.
Definition analyzer.h:730
PrimExpr Simplify(const PrimExpr &expr, int steps=2)
Simplify expr.
bool CanProveGreaterEqual(const PrimExpr &expr, int64_t lower_bound)
Whether can we prove expr >= val.
bool CanProveLessEqualThanSymbolicShapeValue(const PrimExpr &lhs, const PrimExpr &shape)
Whether we can prove lhs is smaller than possibly symbolic shape.
Analyzer Clone() const
Deep-copy this analyzer into a new, independent Analyzer.
bool CanProveLess(const PrimExpr &expr, int64_t upper_bound)
Whether can we prove expr < val.
AnalyzerObj()
constructor
bool CanProve(const PrimExpr &cond, ProofStrength strength=ProofStrength::kDefault)
Whether can we prove condition.
ConstIntBoundAnalyzer const_int_bound
sub-analyzer: const integer bound
Definition analyzer.h:733
Z3Prover z3_prover
sub-analyzer using Z3
Definition analyzer.h:745
void Bind(const ffi::Map< Var, Range > &variables, bool allow_override=false)
Bind all the vars in the Map.
void Bind(const Var &var, const Range &range, bool allow_override=false)
Notify all the sub-analyzers that var is created and bound to a range.
void MarkGlobalNonNegValue(const PrimExpr &value)
Mark the value as non-negative value globally in analyzer.
RewriteSimplifier rewrite_simplify
sub-analyzer rewrite simplify
Definition analyzer.h:737
IntSetAnalyzer int_set
sub-analyzer: int set
Definition analyzer.h:741
void Bind(const Var &var, const PrimExpr &expr, bool allow_override=false)
Notify all the sub-analyzers that var is created and binded to expr.
TransitiveComparisonAnalyzer transitive_comparisons
sub-analyzer transitive comparisons
Definition analyzer.h:743
bool CanProveEqual(const PrimExpr &lhs, const PrimExpr &rhs)
Whether can we prove lhs == rhs.
ModularSetAnalyzer modular_set
sub-analyzer: modular set
Definition analyzer.h:735
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.Analyzer", AnalyzerObj, ffi::Object)
CanonicalSimplifier canonical_simplify
sub-analyzer canonical simplify
Definition analyzer.h:739
Managed reference to AnalyzerObj.
Definition analyzer.h:931
Analyzer(ffi::ObjectPtr< AnalyzerObj > n)
Definition analyzer.h:935
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Analyzer, ffi::ObjectRef, AnalyzerObj)
Analyzer()
Default-construct a fresh analyzer (allocates an AnalyzerObj).
Definition analyzer.h:934
Canonical-form based simplifier.
Definition analyzer.h:429
PrimExpr operator()(const PrimExpr &expr)
analyze the expr
void Update(const Var &var, const PrimExpr &new_expr, bool allow_override=false)
Update binding of var to a new expression.
Analyzer to get constant integer bound over expression.
Definition analyzer.h:135
bool IsBound(const Var &var) const
Check if a variable is bound to a range.
void Update(const Var &var, const ConstIntBound &info, bool allow_override=false)
Update constant int bound information of var.
std::unordered_map< PrimExpr, ConstIntBound, ffi::ObjectPtrHash, ffi::ObjectPtrEqual > BoundMapType
Definition analyzer.h:138
void Bind(const Var &var, const Range &range, bool allow_override=false)
Bind variable to a range.
ConstIntBound operator()(const PrimExpr &expr, BoundMapType *bound)
analyze the expr with the intermediate memorized to avoid redundant computation
ConstIntBound operator()(const PrimExpr &expr) const
analyze the expr
Constant integer up and lower bound(inclusive). Useful for value bound analysis.
Definition analyzer.h:90
static const constexpr int64_t kPosInf
Number to represent +inf.
Definition analyzer.h:103
int64_t min_value
Definition analyzer.h:92
static const constexpr int64_t kNegInf
Number to represent -inf.
Definition analyzer.h:108
int64_t max_value
Definition analyzer.h:93
static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind
Definition analyzer.h:110
static void RegisterReflection()
Definition analyzer.h:95
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.ConstIntBound", ConstIntBoundNode, ffi::Object)
reference class to ConstIntBoundNode
Definition analyzer.h:118
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(ConstIntBound, ffi::ObjectRef, ConstIntBoundNode)
static const constexpr int64_t kNegInf
Definition analyzer.h:128
ConstIntBound(int64_t min_value, int64_t max_value)
constructor by fields.
static const constexpr int64_t kPosInf
Definition analyzer.h:127
Constraint context.
Definition analyzer.h:957
Integer set analyzer.
Definition analyzer.h:547
std::function< void()> EnterConstraint(const PrimExpr &constraint)
void Update(const Var &var, const IntSet &new_interval_set, bool allow_override=false)
Update binding of var to a new expression.
void Bind(const Var &var, const Range &new_range, bool allow_override=false)
Update binding of var to a new expression.
IntSet operator()(const PrimExpr &expr, const ffi::Map< Var, IntSet > &dom_map)
Find a symbolic integer set that contains all possible values of expr given the domain of each variab...
IntSet operator()(const PrimExpr &expr)
Find a symbolic integer set that contains all possible values of expr given the domain of each variab...
Managed reference to IntSetNode.
Definition int_set.h:68
Analyzer to get modular information over expression.
Definition analyzer.h:242
void Update(const Var &var, const ModularSet &info, bool allow_override=false)
Update constant int bound information of var.
ModularSet operator()(const PrimExpr &expr)
analyze the expr
Range of a linear integer function. Use to do specify the possible index values.
Definition analyzer.h:210
int64_t coeff
linear co-efficient
Definition analyzer.h:213
static void RegisterReflection()
Definition analyzer.h:217
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("arith.ModularSet", ModularSetNode, ffi::Object)
static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind
Definition analyzer.h:224
int64_t base
The base.
Definition analyzer.h:215
reference of ModularSetNode
Definition analyzer.h:232
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(ModularSet, ffi::ObjectRef, ModularSetNode)
ModularSet(int64_t coeff, int64_t base)
Rewrite-rule based simplifier.
Definition analyzer.h:281
Extension GetEnabledExtensions() const
Return the currently enabled extensions.
ffi::ObjectRef GetStatsCounters() const
Return the statistics counters.
void SetEnabledExtensions(Extension flags)
Enable an optional extension or extensions.
std::function< void()> EnterConstraint(const PrimExpr &constraint, bool is_assume=false)
Update the internal state to enter constraint.
void Update(const Var &var, const PrimExpr &new_expr, bool allow_override=false)
Update binding of var to a new expression.
Extension
Flags to enable more computationally-intensive simplifications.
Definition analyzer.h:320
@ kNone
Definition analyzer.h:322
@ kApplyConstraintsToBooleanBranches
Definition analyzer.h:350
@ kTransitivelyProveInequalities
Definition analyzer.h:329
@ kComparisonOfProductAndSum
Definition analyzer.h:379
@ kConvertBooleanToAndOfOrs
Definition analyzer.h:337
void SetMaximumRewriteSteps(int64_t maximum)
Set the maximum allowed number of rewrite steps.
void ResetStatsCounters()
Reset the statistics counters.
PrimExpr operator()(const PrimExpr &expr)
analyze the expr
Using previously specified knowns, compare the expressions provided.
Definition analyzer.h:487
std::function< void()> EnterConstraint(const PrimExpr &constraint)
Update the internal state to enter constraint.
void Bind(const Var &var, const Range &range, bool allow_override=false)
Bind a variable as being within a specified range.
void Bind(const Var &var, const PrimExpr &expr, bool allow_override=false)
Bind a variable as being equal to a known expression.
CompareResult TryCompare(const PrimExpr &lhs, const PrimExpr &rhs, bool propagate_inequalities=true)
Definition analyzer.h:615
std::function< void()> EnterConstraint(const PrimExpr &constraint, bool is_assume=false)
Update the internal state to enter constraint.
ffi::String GetModel(const PrimExpr &expr)
Get the Z3 model for the given expression if satisfiable.
void SetTimeoutMs(unsigned timeout_ms)
Set timeout in milliseconds for Z3 prover.
void Bind(const Var &var, const Range &new_range, bool allow_override=false)
Update binding of var to a new expression.
bool CanProve(const PrimExpr &expr)
Whether can we prove expr is always true.
bool IsEnabled() const
Whether the Z3 backend is compiled into this build (USE_Z3=ON).
ffi::String GetStats()
Get statistics about Z3 prover.
int64_t CountSatisfyingValues(const Var &var, int64_t max_count=2048, int64_t min_consecutive=1)
Count the number of integer values that satisfy the current constraints.
ffi::String GetSMTLIB2(const ffi::Optional< PrimExpr > expr)
Get the SMTLIB2 representation of the current context.
void Bind(const Var &var, const PrimExpr &expr, bool allow_override=false)
Update binding of var to a new expression.
void SetRLimit(unsigned rlimit)
Set resource limitation for Z3 prover.
Integer set.
Base expr nodes in TVM.
ProofStrength
The strength used in top-level condition proves.
Definition analyzer.h:75
@ kSymbolicBound
Prove using symbolic bound analysis.
@ kDefault
default strength, can be used in.
CompareResult
Structure for representing result of known.
Definition analyzer.h:463
constexpr CompareResult operator|(CompareResult lhs, CompareResult rhs)
Definition analyzer.h:477
void EnterZ3ContextScope()
Enter a thread-local Z3 context scope.
void ExitZ3ContextScope()
Exit the current thread-local Z3 context scope.
DivMode
Definition analyzer.h:61
@ kTruncDiv
Truncated division.
Definition analyzer.h:63
@ kFloorDiv
Floor division.
Definition analyzer.h:65
@ kUnknown
Definition int_set.h:52
constexpr CompareResult operator&(CompareResult lhs, CompareResult rhs)
Definition analyzer.h:474
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition analyzer.h:40
PrimExpr max_value(PrimType dtype, Span span=Span())
PrimExpr min_value(PrimType dtype, Span span=Span())
RAII wrapper function to enter and exit a context object similar to python's with syntax.