195aff23eSKrzysztof Drewniak //===- TestIntRangeInference.cpp - Create consts from range inference ---===//
295aff23eSKrzysztof Drewniak //
395aff23eSKrzysztof Drewniak // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
495aff23eSKrzysztof Drewniak // See https://llvm.org/LICENSE.txt for license information.
595aff23eSKrzysztof Drewniak // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
695aff23eSKrzysztof Drewniak //
795aff23eSKrzysztof Drewniak //===----------------------------------------------------------------------===//
895aff23eSKrzysztof Drewniak // TODO: This pass is needed to test integer range inference until that
995aff23eSKrzysztof Drewniak // functionality has been integrated into SCCP.
1095aff23eSKrzysztof Drewniak //===----------------------------------------------------------------------===//
1195aff23eSKrzysztof Drewniak
12ab701975SMogball #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
13ab701975SMogball #include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
1495aff23eSKrzysztof Drewniak #include "mlir/Interfaces/SideEffectInterfaces.h"
1595aff23eSKrzysztof Drewniak #include "mlir/Pass/Pass.h"
1695aff23eSKrzysztof Drewniak #include "mlir/Pass/PassRegistry.h"
1795aff23eSKrzysztof Drewniak #include "mlir/Support/TypeID.h"
1895aff23eSKrzysztof Drewniak #include "mlir/Transforms/FoldUtils.h"
1995aff23eSKrzysztof Drewniak
2095aff23eSKrzysztof Drewniak using namespace mlir;
21ab701975SMogball using namespace mlir::dataflow;
2295aff23eSKrzysztof Drewniak
2395aff23eSKrzysztof Drewniak /// Patterned after SCCP
replaceWithConstant(DataFlowSolver & solver,OpBuilder & b,OperationFolder & folder,Value value)24ab701975SMogball static LogicalResult replaceWithConstant(DataFlowSolver &solver, OpBuilder &b,
25ab701975SMogball OperationFolder &folder, Value value) {
26ab701975SMogball auto *maybeInferredRange =
27ab701975SMogball solver.lookupState<IntegerValueRangeLattice>(value);
28ab701975SMogball if (!maybeInferredRange || maybeInferredRange->isUninitialized())
2995aff23eSKrzysztof Drewniak return failure();
30ab701975SMogball const ConstantIntRanges &inferredRange =
31ab701975SMogball maybeInferredRange->getValue().getValue();
3295aff23eSKrzysztof Drewniak Optional<APInt> maybeConstValue = inferredRange.getConstantValue();
33*491d2701SKazu Hirata if (!maybeConstValue.has_value())
3495aff23eSKrzysztof Drewniak return failure();
3595aff23eSKrzysztof Drewniak
3695aff23eSKrzysztof Drewniak Operation *maybeDefiningOp = value.getDefiningOp();
3795aff23eSKrzysztof Drewniak Dialect *valueDialect =
3895aff23eSKrzysztof Drewniak maybeDefiningOp ? maybeDefiningOp->getDialect()
3995aff23eSKrzysztof Drewniak : value.getParentRegion()->getParentOp()->getDialect();
4095aff23eSKrzysztof Drewniak Attribute constAttr = b.getIntegerAttr(value.getType(), *maybeConstValue);
4195aff23eSKrzysztof Drewniak Value constant = folder.getOrCreateConstant(b, valueDialect, constAttr,
4295aff23eSKrzysztof Drewniak value.getType(), value.getLoc());
4395aff23eSKrzysztof Drewniak if (!constant)
4495aff23eSKrzysztof Drewniak return failure();
4595aff23eSKrzysztof Drewniak
4695aff23eSKrzysztof Drewniak value.replaceAllUsesWith(constant);
4795aff23eSKrzysztof Drewniak return success();
4895aff23eSKrzysztof Drewniak }
4995aff23eSKrzysztof Drewniak
rewrite(DataFlowSolver & solver,MLIRContext * context,MutableArrayRef<Region> initialRegions)50ab701975SMogball static void rewrite(DataFlowSolver &solver, MLIRContext *context,
5195aff23eSKrzysztof Drewniak MutableArrayRef<Region> initialRegions) {
5295aff23eSKrzysztof Drewniak SmallVector<Block *> worklist;
5395aff23eSKrzysztof Drewniak auto addToWorklist = [&](MutableArrayRef<Region> regions) {
5495aff23eSKrzysztof Drewniak for (Region ®ion : regions)
5595aff23eSKrzysztof Drewniak for (Block &block : llvm::reverse(region))
5695aff23eSKrzysztof Drewniak worklist.push_back(&block);
5795aff23eSKrzysztof Drewniak };
5895aff23eSKrzysztof Drewniak
5995aff23eSKrzysztof Drewniak OpBuilder builder(context);
6095aff23eSKrzysztof Drewniak OperationFolder folder(context);
6195aff23eSKrzysztof Drewniak
6295aff23eSKrzysztof Drewniak addToWorklist(initialRegions);
6395aff23eSKrzysztof Drewniak while (!worklist.empty()) {
6495aff23eSKrzysztof Drewniak Block *block = worklist.pop_back_val();
6595aff23eSKrzysztof Drewniak
6695aff23eSKrzysztof Drewniak for (Operation &op : llvm::make_early_inc_range(*block)) {
6795aff23eSKrzysztof Drewniak builder.setInsertionPoint(&op);
6895aff23eSKrzysztof Drewniak
6995aff23eSKrzysztof Drewniak // Replace any result with constants.
7095aff23eSKrzysztof Drewniak bool replacedAll = op.getNumResults() != 0;
7195aff23eSKrzysztof Drewniak for (Value res : op.getResults())
7295aff23eSKrzysztof Drewniak replacedAll &=
73ab701975SMogball succeeded(replaceWithConstant(solver, builder, folder, res));
7495aff23eSKrzysztof Drewniak
7595aff23eSKrzysztof Drewniak // If all of the results of the operation were replaced, try to erase
7695aff23eSKrzysztof Drewniak // the operation completely.
7795aff23eSKrzysztof Drewniak if (replacedAll && wouldOpBeTriviallyDead(&op)) {
7895aff23eSKrzysztof Drewniak assert(op.use_empty() && "expected all uses to be replaced");
7995aff23eSKrzysztof Drewniak op.erase();
8095aff23eSKrzysztof Drewniak continue;
8195aff23eSKrzysztof Drewniak }
8295aff23eSKrzysztof Drewniak
8395aff23eSKrzysztof Drewniak // Add any the regions of this operation to the worklist.
8495aff23eSKrzysztof Drewniak addToWorklist(op.getRegions());
8595aff23eSKrzysztof Drewniak }
8695aff23eSKrzysztof Drewniak
8795aff23eSKrzysztof Drewniak // Replace any block arguments with constants.
8895aff23eSKrzysztof Drewniak builder.setInsertionPointToStart(block);
8995aff23eSKrzysztof Drewniak for (BlockArgument arg : block->getArguments())
90ab701975SMogball (void)replaceWithConstant(solver, builder, folder, arg);
9195aff23eSKrzysztof Drewniak }
9295aff23eSKrzysztof Drewniak }
9395aff23eSKrzysztof Drewniak
9495aff23eSKrzysztof Drewniak namespace {
9595aff23eSKrzysztof Drewniak struct TestIntRangeInference
9695aff23eSKrzysztof Drewniak : PassWrapper<TestIntRangeInference, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anonee8f13ed0211::TestIntRangeInference9795aff23eSKrzysztof Drewniak MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestIntRangeInference)
9895aff23eSKrzysztof Drewniak
9995aff23eSKrzysztof Drewniak StringRef getArgument() const final { return "test-int-range-inference"; }
getDescription__anonee8f13ed0211::TestIntRangeInference10095aff23eSKrzysztof Drewniak StringRef getDescription() const final {
10195aff23eSKrzysztof Drewniak return "Test integer range inference analysis";
10295aff23eSKrzysztof Drewniak }
10395aff23eSKrzysztof Drewniak
runOnOperation__anonee8f13ed0211::TestIntRangeInference10495aff23eSKrzysztof Drewniak void runOnOperation() override {
10595aff23eSKrzysztof Drewniak Operation *op = getOperation();
106ab701975SMogball DataFlowSolver solver;
107ab701975SMogball solver.load<DeadCodeAnalysis>();
108ab701975SMogball solver.load<IntegerRangeAnalysis>();
109ab701975SMogball if (failed(solver.initializeAndRun(op)))
110ab701975SMogball return signalPassFailure();
111ab701975SMogball rewrite(solver, op->getContext(), op->getRegions());
11295aff23eSKrzysztof Drewniak }
11395aff23eSKrzysztof Drewniak };
11495aff23eSKrzysztof Drewniak } // end anonymous namespace
11595aff23eSKrzysztof Drewniak
11695aff23eSKrzysztof Drewniak namespace mlir {
11795aff23eSKrzysztof Drewniak namespace test {
registerTestIntRangeInference()11895aff23eSKrzysztof Drewniak void registerTestIntRangeInference() {
11995aff23eSKrzysztof Drewniak PassRegistration<TestIntRangeInference>();
12095aff23eSKrzysztof Drewniak }
12195aff23eSKrzysztof Drewniak } // end namespace test
12295aff23eSKrzysztof Drewniak } // end namespace mlir
123