10#include "mlir/Interfaces/SideEffectInterfaces.h"
13#include "llvm/Support/DebugLog.h"
15#define DEBUG_TYPE "cir-basic-alias-analysis"
26mlir::Value CIRBasicAliasAnalysis::getUnderlyingObject(mlir::Value val) {
27 LDBG() <<
"Getting underlying object for: " << val;
30 mlir::Operation *defOp = val.getDefiningOp();
32 LDBG() <<
"No defining operation, stopping";
39 if (
auto castOp = mlir::dyn_cast<cir::CastOp>(defOp)) {
40 if (castOp.isAllocaPreservingCast() ||
41 castOp.getKind() == cir::CastKind::array_to_ptrdecay) {
42 LDBG() <<
"Walking past cast operation";
43 val = castOp.getSrc();
46 LDBG() <<
"Opaque cast operation, stopping";
52 if (
auto strideOp = mlir::dyn_cast<cir::PtrStrideOp>(defOp)) {
53 auto constOp = strideOp.getStride().getDefiningOp<cir::ConstantOp>();
55 if (
auto intAttr = mlir::dyn_cast<cir::IntAttr>(constOp.getValue())) {
56 APInt stride = intAttr.getValue();
59 if (stride.isZero()) {
60 LDBG() <<
"Walking past zero-strided PtrStrideOp";
61 val = strideOp.getBase();
67 LDBG() <<
"Non-zero or dynamic PtrStrideOp, stopping";
72 if (
auto op = mlir::dyn_cast<cir::GetMemberOp>(defOp)) {
73 if (op.getIndex() == 0) {
74 LDBG() <<
"GetMemberOp[0], following to underlying object";
78 LDBG() <<
"GetMemberOp, non-zero index, stopping";
82 if (
auto op = mlir::dyn_cast<cir::GetElementOp>(defOp)) {
84 if (
auto constOp = op.getIndex().getDefiningOp<cir::ConstantOp>())
85 index = mlir::dyn_cast<cir::IntAttr>(constOp.getValue());
86 if (index && index.getValue().isZero()) {
87 LDBG() <<
"GetElementOp[0], following to underlying object";
91 LDBG() <<
"GetElementOp, non-zero or dynamic index, stopping";
94 if (
auto op = mlir::dyn_cast<cir::BaseClassAddrOp>(defOp)) {
97 if (op.getOffset().isZero()) {
98 LDBG() <<
"BaseClassAddrOp[0], following to underlying object";
99 val = op.getDerivedAddr();
102 LDBG() <<
"BaseClassAddrOp, non-zero offset, stopping";
105 if (
auto op = mlir::dyn_cast<cir::DerivedClassAddrOp>(defOp)) {
109 if (op.getOffset().isZero()) {
110 LDBG() <<
"DerivedClassAddrOp[0], following to underlying object";
111 val = op.getBaseAddr();
114 LDBG() <<
"DerivedClassAddrOp, non-zero offset, stopping";
117 if (
auto op = mlir::dyn_cast<cir::ComplexRealPtrOp>(defOp)) {
118 LDBG() <<
"Getting input pointer for ComplexRealPtrOp";
119 val = op.getOperand();
122 if (
auto op = mlir::dyn_cast<cir::ComplexImagPtrOp>(defOp)) {
123 LDBG() <<
"ComplexImagPtrOp, stopping";
127 LDBG() <<
"Unhandled operation, stopping";
133CIRBasicAliasAnalysis::ObjectRelation
134CIRBasicAliasAnalysis::classifyObjects(mlir::Value lhs, mlir::Value rhs) {
135 LDBG() <<
"Checking if " << lhs <<
" and " << rhs <<
" are distinct objects";
141 mlir::Value lhsObj = getUnderlyingObject(lhs);
142 mlir::Value rhsObj = getUnderlyingObject(rhs);
144 if (lhsObj == rhsObj) {
145 LDBG() <<
"Identical values, not distinct";
146 return ObjectRelation::Identical;
150 if (mlir::isa_and_nonnull<cir::AllocaOp>(lhsObj.getDefiningOp()) &&
151 mlir::isa_and_nonnull<cir::AllocaOp>(rhsObj.getDefiningOp())) {
152 LDBG() <<
"Different cir.alloca ops in the same function, distinct";
153 return ObjectRelation::Distinct;
156 LDBG() <<
"Conservative fallback, not distinct";
157 return ObjectRelation::Unknown;
166 LDBG() <<
"Checking alias between: " << lhs <<
" and " << rhs;
169 LDBG() <<
"Trivial alias between identical values";
170 return mlir::AliasResult::MustAlias;
173 ObjectRelation relation = classifyObjects(lhs, rhs);
175 case ObjectRelation::Distinct:
176 LDBG() <<
"No alias between distinct objects";
177 return mlir::AliasResult::NoAlias;
178 case ObjectRelation::Identical:
179 LDBG() <<
"Must alias between identical objects";
180 return mlir::AliasResult::MustAlias;
181 case ObjectRelation::Unknown:
183 LDBG() <<
"Conservative fallback, may alias";
184 return mlir::AliasResult::MayAlias;
186 llvm_unreachable(
"Unhandled ObjectRelation");
190 mlir::Value location) {
191 LDBG() <<
"getModRef: "
192 << mlir::OpWithFlags(op, mlir::OpPrintingFlags().skipRegions())
193 <<
" on location " << location;
195 auto effects = mlir::dyn_cast<mlir::MemoryEffectOpInterface>(op);
197 LDBG() <<
"No memory effect interface, returning ModAndRef";
198 return mlir::ModRefResult::getModAndRef();
202 effects.getEffects(effectList);
204 auto classifyEffect = [location,
this](
205 const mlir::MemoryEffects::EffectInstance &effect) {
206 if (mlir::isa<mlir::MemoryEffects::Allocate>(effect.getEffect())) {
207 LDBG() <<
"Skipping allocate effect";
208 return mlir::ModRefResult::getNoModRef();
211 mlir::AliasResult aliasResult = mlir::AliasResult::MayAlias;
212 if (mlir::Value affectedLocation = effect.getValue()) {
213 LDBG() <<
" Checking alias between affected location "
214 << affectedLocation <<
" and query location " << location;
215 aliasResult =
alias(affectedLocation, location);
216 LDBG() <<
" Alias result: "
217 << (aliasResult.isMust() ?
"MustAlias"
218 : aliasResult.isNo() ?
"NoAlias"
223 if (!effect.getResource()->isAddressable()) {
224 LDBG() <<
" Effect on non-addressable resource '"
225 << effect.getResource()->getName() <<
"', skipping (NoAlias)";
226 aliasResult = mlir::AliasResult::NoAlias;
228 LDBG() <<
" No effect value, assuming MayAlias";
234 if (aliasResult.isNo()) {
235 LDBG() <<
"No alias with affected location";
236 return mlir::ModRefResult::getNoModRef();
240 if (mlir::isa<mlir::MemoryEffects::Free>(effect.getEffect())) {
241 LDBG() <<
"Skipping free effect";
242 return mlir::ModRefResult::getModAndRef();
245 if (mlir::isa<mlir::MemoryEffects::Write>(effect.getEffect())) {
246 LDBG() <<
"Write effect, adding Mod";
247 return mlir::ModRefResult::getMod();
250 if (mlir::isa<mlir::MemoryEffects::Read>(effect.getEffect())) {
251 LDBG() <<
"Read effect, adding Ref";
252 return mlir::ModRefResult::getRef();
255 LDBG() <<
"Unexpected memory effect: " << effect.getEffect();
256 return mlir::ModRefResult::getNoModRef();
259 return llvm::accumulate(llvm::map_range(effectList, classifyEffect),
260 mlir::ModRefResult::getNoModRef(),
261 [](mlir::ModRefResult lhs, mlir::ModRefResult rhs) {
262 return lhs.merge(rhs);
static constexpr unsigned MaxLookupDepth
mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location)
Return the modify-reference behavior of op on location.
mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs)
Return the aliasing behavior between two values.
Diagnostic wrappers for TextAPI types for error reporting.