CIRCT 24.0.0git
Loading...
Searching...
No Matches
IntRangeAnnotations.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
11#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
12#include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
13#include "mlir/Analysis/DataFlowFramework.h"
14#include "mlir/Transforms/WalkPatternRewriteDriver.h"
15
16using namespace circt;
17using namespace circt::comb;
18using namespace mlir;
19using namespace mlir::dataflow;
20
21namespace circt {
22namespace comb {
23#define GEN_PASS_DEF_COMBOVERFLOWANNOTATING
24#include "circt/Dialect/Comb/Passes.h.inc"
25} // namespace comb
26} // namespace circt
27
28/// Gather ranges for all the values in `values`. Appends to the existing
29/// vector.
30static LogicalResult collectRanges(DataFlowSolver &solver, ValueRange values,
31 SmallVectorImpl<ConstantIntRanges> &ranges) {
32 for (Value val : values) {
33 auto *maybeInferredRange =
34 solver.lookupState<IntegerValueRangeLattice>(val);
35 if (!maybeInferredRange || maybeInferredRange->getValue().isUninitialized())
36 return failure();
37
38 const ConstantIntRanges &inferredRange =
39 maybeInferredRange->getValue().getValue();
40 ranges.push_back(inferredRange);
41 }
42 return success();
43}
44
45namespace {
46template <typename CombOpTy>
47struct CombOpAnnotate : public OpRewritePattern<CombOpTy> {
48 CombOpAnnotate(MLIRContext *context, DataFlowSolver &s)
49 : OpRewritePattern<CombOpTy>(context), solver(s) {}
50
51 LogicalResult matchAndRewrite(CombOpTy op,
52 PatternRewriter &rewriter) const override {
53 // Use LLVM nuw attribute to avoid confusion with IEEE overflow flags
54 if (op->hasAttr("comb.nuw"))
55 return failure();
56
57 if (op->getNumOperands() != 2 || op->getNumResults() != 1)
58 return rewriter.notifyMatchFailure(
59 op, "Only support binary operations with one result");
60
61 assert(isa<comb::AddOp>(op) || isa<comb::MulOp>(op) ||
62 isa<comb::SubOp>(op));
63
64 SmallVector<ConstantIntRanges> ranges;
65 if (failed(collectRanges(solver, op->getOperands(), ranges)))
66 return rewriter.notifyMatchFailure(op, "input without specified range");
67
68 bool overflowed = false;
69 // overflowed = a.max op b.max > 2^(bitwidth)-1
70 auto a = ranges[0].umax();
71 auto b = ranges[1].umax();
72
73 // Only use the overflow flag - need to explicitly discard the result.
74 // Cannot use operators intervals since they will be truncated to the
75 // result's bitwidth.
76 if (isa<comb::AddOp>(op))
77 (void)a.uadd_ov(b, overflowed);
78
79 if (isa<comb::MulOp>(op))
80 (void)a.umul_ov(b, overflowed);
81
82 if (!overflowed)
83 op->setAttr("comb.nuw", UnitAttr::get(op->getContext()));
84
85 return success();
86 }
87
88private:
89 DataFlowSolver &solver;
90};
91
92struct CombOverflowAnnotatingPass
93 : comb::impl::CombOverflowAnnotatingBase<CombOverflowAnnotatingPass> {
94
95 using CombOverflowAnnotatingBase::CombOverflowAnnotatingBase;
96 void runOnOperation() override;
97};
98} // namespace
99
100void CombOverflowAnnotatingPass::runOnOperation() {
101 Operation *op = getOperation();
102 MLIRContext *ctx = op->getContext();
103 DataFlowSolver solver;
104 solver.load<DeadCodeAnalysis>();
105 solver.load<IntegerRangeAnalysis>();
106 if (failed(solver.initializeAndRun(op)))
107 return signalPassFailure();
108
109 RewritePatternSet patterns(ctx);
110 // TODO: determine how to support subtraction
111 patterns.add<CombOpAnnotate<comb::AddOp>, CombOpAnnotate<comb::MulOp>>(
112 patterns.getContext(), solver);
113
114 walkAndApplyPatterns(op, std::move(patterns));
115}
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static LogicalResult collectRanges(DataFlowSolver &solver, ValueRange values, SmallVectorImpl< ConstantIntRanges > &ranges)
Gather ranges for all the values in values.
false return failure()
Parse an optional keyword or string and set instance into 'result'.
return success()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.