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 &region : 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