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 12*ab701975SMogball #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h" 13*ab701975SMogball #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; 21*ab701975SMogball using namespace mlir::dataflow; 2295aff23eSKrzysztof Drewniak 2395aff23eSKrzysztof Drewniak /// Patterned after SCCP 24*ab701975SMogball static LogicalResult replaceWithConstant(DataFlowSolver &solver, OpBuilder &b, 25*ab701975SMogball OperationFolder &folder, Value value) { 26*ab701975SMogball auto *maybeInferredRange = 27*ab701975SMogball solver.lookupState<IntegerValueRangeLattice>(value); 28*ab701975SMogball if (!maybeInferredRange || maybeInferredRange->isUninitialized()) 2995aff23eSKrzysztof Drewniak return failure(); 30*ab701975SMogball const ConstantIntRanges &inferredRange = 31*ab701975SMogball maybeInferredRange->getValue().getValue(); 3295aff23eSKrzysztof Drewniak Optional<APInt> maybeConstValue = inferredRange.getConstantValue(); 333b7c3a65SKazu Hirata if (!maybeConstValue.hasValue()) 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 50*ab701975SMogball 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 &= 73*ab701975SMogball 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()) 90*ab701975SMogball (void)replaceWithConstant(solver, builder, folder, arg); 9195aff23eSKrzysztof Drewniak } 9295aff23eSKrzysztof Drewniak } 9395aff23eSKrzysztof Drewniak 9495aff23eSKrzysztof Drewniak namespace { 9595aff23eSKrzysztof Drewniak struct TestIntRangeInference 9695aff23eSKrzysztof Drewniak : PassWrapper<TestIntRangeInference, OperationPass<>> { 9795aff23eSKrzysztof Drewniak MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestIntRangeInference) 9895aff23eSKrzysztof Drewniak 9995aff23eSKrzysztof Drewniak StringRef getArgument() const final { return "test-int-range-inference"; } 10095aff23eSKrzysztof Drewniak StringRef getDescription() const final { 10195aff23eSKrzysztof Drewniak return "Test integer range inference analysis"; 10295aff23eSKrzysztof Drewniak } 10395aff23eSKrzysztof Drewniak 10495aff23eSKrzysztof Drewniak void runOnOperation() override { 10595aff23eSKrzysztof Drewniak Operation *op = getOperation(); 106*ab701975SMogball DataFlowSolver solver; 107*ab701975SMogball solver.load<DeadCodeAnalysis>(); 108*ab701975SMogball solver.load<IntegerRangeAnalysis>(); 109*ab701975SMogball if (failed(solver.initializeAndRun(op))) 110*ab701975SMogball return signalPassFailure(); 111*ab701975SMogball 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 { 11895aff23eSKrzysztof Drewniak void registerTestIntRangeInference() { 11995aff23eSKrzysztof Drewniak PassRegistration<TestIntRangeInference>(); 12095aff23eSKrzysztof Drewniak } 12195aff23eSKrzysztof Drewniak } // end namespace test 12295aff23eSKrzysztof Drewniak } // end namespace mlir 123