Enzyme main
Loading...
Searching...
No Matches
PrintAliasAnalysis.cpp
Go to the documentation of this file.
1//===- PrintAliasAnalysis.cpp - Pass to print alias analysis --------------===//
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//
9// This file implements a pass to print the results of running alias
10// analysis.
11//
12//===----------------------------------------------------------------------===//
13
15#include "Dialect/Ops.h"
17#include "Passes/PassDetails.h"
18#include "Passes/Passes.h"
19
20#include "mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h"
21#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
22#include "mlir/Interfaces/FunctionInterfaces.h"
23
24using namespace mlir;
25using namespace mlir::enzyme;
26
27namespace mlir {
28namespace enzyme {
29#define GEN_PASS_DEF_PRINTALIASANALYSISPASS
30#include "Passes/Passes.h.inc"
31} // namespace enzyme
32} // namespace mlir
33
34namespace {
35
36struct PrintAliasAnalysisPass
37 : public enzyme::impl::PrintAliasAnalysisPassBase<PrintAliasAnalysisPass> {
38
39 void runOnOperation() override {
40 DataFlowSolver solver;
41
42 solver.load<enzyme::AliasAnalysis>(&getContext());
44 solver.load<dataflow::DeadCodeAnalysis>();
45 solver.load<dataflow::SparseConstantPropagation>();
46
47 if (failed(solver.initializeAndRun(getOperation()))) {
48 return signalPassFailure();
49 }
50 raw_ostream &os = llvm::outs();
51
52 SmallVector<std::pair<Attribute, Value>> taggedPointers;
53 getOperation()->walk([&](FunctionOpInterface funcOp) {
54 for (auto arg : funcOp.getArguments()) {
55 if (funcOp.getArgAttr(arg.getArgNumber(), "enzyme.tag")) {
56 taggedPointers.push_back(
57 {funcOp.getArgAttr(arg.getArgNumber(), "enzyme.tag"), arg});
58 }
59 }
60
61 funcOp.walk([&](Operation *op) {
62 if (op->hasAttr("tag")) {
63 for (OpResult result : op->getResults()) {
64 taggedPointers.push_back({op->getAttr("tag"), result});
65 }
66 }
67 });
68 });
69
70 for (const auto &[tag, value] : taggedPointers) {
71 const auto *state = solver.lookupState<enzyme::AliasClassLattice>(value);
72 if (state) {
73 os << "tag " << tag << " " << *state << "\n";
74 }
75 }
76
77 if (taggedPointers.empty())
78 return;
79
80 // Compare all tagged pointers
81 for (unsigned i = 0; i < taggedPointers.size() - 1; i++) {
82 for (unsigned j = i + 1; j < taggedPointers.size(); j++) {
83 const auto &[tagA, a] = taggedPointers[i];
84 const auto &[tagB, b] = taggedPointers[j];
85
86 const auto *lhs = solver.lookupState<enzyme::AliasClassLattice>(a);
87 const auto *rhs = solver.lookupState<enzyme::AliasClassLattice>(b);
88 if (!(lhs && rhs))
89 continue;
90
91 os << tagA << " and " << tagB << ": " << lhs->alias(*rhs) << "\n";
92 }
93 }
94
95 getOperation()->walk([&solver, &os](Operation *op) {
96 if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
97 for (auto arg : funcOp.getArguments()) {
98 auto *state = solver.lookupState<enzyme::AliasClassLattice>(arg);
99 if (!state)
100 continue;
101 // TODO(zinenko): this has been overriding the argument...
102 // Use an array attr instead (will break syntactic tests).
104 [&](DistinctAttr aliasClass, enzyme::AliasClassSet::State state) {
105 if (state == enzyme::AliasClassSet::State::Undefined)
106 funcOp.setArgAttr(
107 arg.getArgNumber(), "enzyme.ac",
108 StringAttr::get(arg.getContext(), "undefined"));
109 else if (state == enzyme::AliasClassSet::State::Unknown)
110 funcOp.setArgAttr(
111 arg.getArgNumber(), "enzyme.ac",
112 StringAttr::get(arg.getContext(), "unknown"));
113 else
114 funcOp.setArgAttr(arg.getArgNumber(), "enzyme.ac",
115 aliasClass);
116 return ChangeResult::NoChange;
117 });
118 }
119 } else if (mlir::enzyme::isFunctionReturnLike(op) &&
120 isa<FunctionOpInterface>(op->getParentOp())) {
121 os << "points-to-pointer sets for op @" << op->getLoc() << ":\n";
122 if (auto *state = solver.lookupState<enzyme::PointsToSets>(
123 solver.getProgramPointBefore(op)))
124 os << *state << "\n";
125 else
126 os << "NOT computed\n";
127 }
128 if (op->hasAttr("tag")) {
129 for (OpResult result : op->getResults()) {
130 auto *state = solver.lookupState<enzyme::AliasClassLattice>(result);
131 if (state) {
132 if (state->isUnknown()) {
133 op->setAttr("ac",
134 StringAttr::get(result.getContext(), "<unknown>"));
135 } else if (state->isUndefined()) {
136 op->setAttr("ac",
137 StringAttr::get(result.getContext(), "<undefined>"));
138 } else {
139 for (auto aliasClass : state->getAliasClasses()) {
140 op->setAttr("ac", aliasClass);
141 }
142 }
143 }
144 }
145 }
146 });
147 }
148};
149} // namespace
This analysis implements interprocedural alias analysis.
const AliasClassSet & getAliasClassesObject() const
::mlir::AliasResult alias(const AbstractSparseLattice &other) const
ChangeResult foreachElement(function_ref< ChangeResult(ValueT, State)> callback) const
bool isFunctionReturnLike(Operation *op)