//===- TestAliasAnalysis.cpp - Test alias analysis results ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains test passes for constructing and testing alias analysis // results. // //===----------------------------------------------------------------------===// #include "TestAliasAnalysis.h" #include "mlir/Analysis/AliasAnalysis.h" #include "mlir/Analysis/AliasAnalysis/LocalAliasAnalysis.h" #include "mlir/Interfaces/FunctionInterfaces.h" #include "mlir/Pass/Pass.h" using namespace mlir; /// Print a value that is used as an operand of an alias query. static void printAliasOperand(Operation *op) { llvm::errs() << op->getAttrOfType("test.ptr").getValue(); } static void printAliasOperand(Value value) { if (BlockArgument arg = dyn_cast(value)) { Region *region = arg.getParentRegion(); unsigned parentBlockNumber = std::distance(region->begin(), arg.getOwner()->getIterator()); llvm::errs() << region->getParentOp() ->getAttrOfType("test.ptr") .getValue() << ".region" << region->getRegionNumber(); if (parentBlockNumber != 0) llvm::errs() << ".block" << parentBlockNumber; llvm::errs() << "#" << arg.getArgNumber(); return; } OpResult result = cast(value); printAliasOperand(result.getOwner()); llvm::errs() << "#" << result.getResultNumber(); } namespace mlir { namespace test { void printAliasResult(AliasResult result, Value lhs, Value rhs) { printAliasOperand(lhs); llvm::errs() << " <-> "; printAliasOperand(rhs); llvm::errs() << ": " << result << "\n"; } /// Print the result of an alias query. void printModRefResult(ModRefResult result, Operation *op, Value location) { printAliasOperand(op); llvm::errs() << " -> "; printAliasOperand(location); llvm::errs() << ": " << result << "\n"; } void TestAliasAnalysisBase::runAliasAnalysisOnOperation( Operation *op, AliasAnalysis &aliasAnalysis) { llvm::errs() << "Testing : " << *op->getInherentAttr("sym_name") << "\n"; // Collect all of the values to check for aliasing behavior. SmallVector valsToCheck; op->walk([&](Operation *op) { if (!op->getDiscardableAttr("test.ptr")) return; valsToCheck.append(op->result_begin(), op->result_end()); for (Region ®ion : op->getRegions()) for (Block &block : region) valsToCheck.append(block.args_begin(), block.args_end()); }); // Check for aliasing behavior between each of the values. for (auto it = valsToCheck.begin(), e = valsToCheck.end(); it != e; ++it) for (auto *innerIt = valsToCheck.begin(); innerIt != it; ++innerIt) printAliasResult(aliasAnalysis.alias(*innerIt, *it), *innerIt, *it); } void TestAliasAnalysisModRefBase::runAliasAnalysisOnOperation( Operation *op, AliasAnalysis &aliasAnalysis) { llvm::errs() << "Testing : " << *op->getInherentAttr("sym_name") << "\n"; // Collect all of the values to check for aliasing behavior. SmallVector valsToCheck; op->walk([&](Operation *op) { if (!op->getDiscardableAttr("test.ptr")) return; valsToCheck.append(op->result_begin(), op->result_end()); for (Region ®ion : op->getRegions()) for (Block &block : region) valsToCheck.append(block.args_begin(), block.args_end()); }); // Check for aliasing behavior between each of the values. for (auto &it : valsToCheck) { op->walk([&](Operation *op) { if (!op->getDiscardableAttr("test.ptr")) return; printModRefResult(aliasAnalysis.getModRef(op, it), op, it); }); } } } // namespace test } // namespace mlir //===----------------------------------------------------------------------===// // Testing AliasResult //===----------------------------------------------------------------------===// namespace { struct TestAliasAnalysisPass : public test::TestAliasAnalysisBase, PassWrapper> { MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAliasAnalysisPass) StringRef getArgument() const final { return "test-alias-analysis"; } StringRef getDescription() const final { return "Test alias analysis results."; } void runOnOperation() override { AliasAnalysis &aliasAnalysis = getAnalysis(); runAliasAnalysisOnOperation(getOperation(), aliasAnalysis); } }; } // namespace //===----------------------------------------------------------------------===// // Testing ModRefResult //===----------------------------------------------------------------------===// namespace { struct TestAliasAnalysisModRefPass : public test::TestAliasAnalysisModRefBase, PassWrapper> { MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAliasAnalysisModRefPass) StringRef getArgument() const final { return "test-alias-analysis-modref"; } StringRef getDescription() const final { return "Test alias analysis ModRef results."; } void runOnOperation() override { AliasAnalysis &aliasAnalysis = getAnalysis(); runAliasAnalysisOnOperation(getOperation(), aliasAnalysis); } }; } // namespace //===----------------------------------------------------------------------===// // Testing LocalAliasAnalysis extending //===----------------------------------------------------------------------===// /// Check if value is function argument. static bool isFuncArg(Value val) { auto blockArg = dyn_cast(val); if (!blockArg) return false; return mlir::isa_and_nonnull( blockArg.getOwner()->getParentOp()); } /// Check if value has "restrict" attribute. Value must be a function argument. static bool isRestrict(Value val) { auto blockArg = cast(val); auto func = mlir::cast(blockArg.getOwner()->getParentOp()); return !!func.getArgAttr(blockArg.getArgNumber(), "local_alias_analysis.restrict"); } namespace { /// LocalAliasAnalysis extended to support "restrict" attreibute. class LocalAliasAnalysisRestrict : public LocalAliasAnalysis { protected: AliasResult aliasImpl(Value lhs, Value rhs) override { if (lhs == rhs) return AliasResult::MustAlias; // Assume no aliasing if both values are function arguments and any of them // have restrict attr. if (isFuncArg(lhs) && isFuncArg(rhs)) if (isRestrict(lhs) || isRestrict(rhs)) return AliasResult::NoAlias; return LocalAliasAnalysis::aliasImpl(lhs, rhs); } }; /// This pass tests adding additional analysis impls to the AliasAnalysis. struct TestAliasAnalysisExtendingPass : public test::TestAliasAnalysisBase, PassWrapper> { MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAliasAnalysisExtendingPass) StringRef getArgument() const final { return "test-alias-analysis-extending"; } StringRef getDescription() const final { return "Test alias analysis extending."; } void runOnOperation() override { AliasAnalysis aliasAnalysis(getOperation()); aliasAnalysis.addAnalysisImplementation(LocalAliasAnalysisRestrict()); runAliasAnalysisOnOperation(getOperation(), aliasAnalysis); } }; } // namespace //===----------------------------------------------------------------------===// // Pass Registration //===----------------------------------------------------------------------===// namespace mlir { namespace test { void registerTestAliasAnalysisPass() { PassRegistration(); PassRegistration(); PassRegistration(); } } // namespace test } // namespace mlir