1//===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -------------------===//
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/// \file
9/// This file defines a simple ARC-aware AliasAnalysis using special knowledge
10/// of Objective C to enhance other optimization passes which rely on the Alias
11/// Analysis infrastructure.
12///
13/// WARNING: This file knows about certain library functions. It recognizes them
14/// by name, and hardwires knowledge of their semantics.
15///
16/// WARNING: This file knows about how certain Objective-C library functions are
17/// used. Naive LLVM IR transformations which would otherwise be
18/// behavior-preserving may break these assumptions.
19///
20/// TODO: Theoretically we could check for dependencies between objc_* calls
21/// and FMRB_OnlyAccessesArgumentPointees calls or other well-behaved calls.
22///
23/// TODO: The calls here to AAResultBase member functions are all effectively
24/// no-ops that just return a conservative result. The original intent was to
25/// chain to another analysis for a recursive query, but this was lost in a
26/// refactor. These should instead be rephrased in terms of queries to AAQI.AAR.
27///
28//===----------------------------------------------------------------------===//
29
30#include "llvm/Analysis/ObjCARCAliasAnalysis.h"
31#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
32#include "llvm/IR/Function.h"
33#include "llvm/Pass.h"
34
35#define DEBUG_TYPE "objc-arc-aa"
36
37using namespace llvm;
38using namespace llvm::objcarc;
39
40AliasResult ObjCARCAAResult::alias(const MemoryLocation &LocA,
41 const MemoryLocation &LocB,
42 AAQueryInfo &AAQI, const Instruction *) {
43 if (!EnableARCOpts)
44 return AAResultBase::alias(LocA, LocB, AAQI, I: nullptr);
45
46 // First, strip off no-ops, including ObjC-specific no-ops, and try making a
47 // precise alias query.
48 const Value *SA = GetRCIdentityRoot(V: LocA.Ptr);
49 const Value *SB = GetRCIdentityRoot(V: LocB.Ptr);
50 AliasResult Result = AAResultBase::alias(
51 LocA: MemoryLocation(SA, LocA.Size, LocA.AATags),
52 LocB: MemoryLocation(SB, LocB.Size, LocB.AATags), AAQI, I: nullptr);
53 if (Result != AliasResult::MayAlias)
54 return Result;
55
56 // If that failed, climb to the underlying object, including climbing through
57 // ObjC-specific no-ops, and try making an imprecise alias query.
58 const Value *UA = GetUnderlyingObjCPtr(V: SA);
59 const Value *UB = GetUnderlyingObjCPtr(V: SB);
60 if (UA != SA || UB != SB) {
61 Result = AAResultBase::alias(LocA: MemoryLocation::getBeforeOrAfter(Ptr: UA),
62 LocB: MemoryLocation::getBeforeOrAfter(Ptr: UB), AAQI,
63 I: nullptr);
64 // We can't use MustAlias or PartialAlias results here because
65 // GetUnderlyingObjCPtr may return an offsetted pointer value.
66 if (Result == AliasResult::NoAlias)
67 return AliasResult::NoAlias;
68 }
69
70 // If that failed, fail. We don't need to chain here, since that's covered
71 // by the earlier precise query.
72 return AliasResult::MayAlias;
73}
74
75ModRefInfo ObjCARCAAResult::getModRefInfoMask(const MemoryLocation &Loc,
76 AAQueryInfo &AAQI,
77 bool IgnoreLocals) {
78 if (!EnableARCOpts)
79 return AAResultBase::getModRefInfoMask(Loc, AAQI, IgnoreLocals);
80
81 // First, strip off no-ops, including ObjC-specific no-ops, and try making
82 // a precise alias query.
83 const Value *S = GetRCIdentityRoot(V: Loc.Ptr);
84 if (isNoModRef(MRI: AAResultBase::getModRefInfoMask(
85 Loc: MemoryLocation(S, Loc.Size, Loc.AATags), AAQI, IgnoreLocals)))
86 return ModRefInfo::NoModRef;
87
88 // If that failed, climb to the underlying object, including climbing through
89 // ObjC-specific no-ops, and try making an imprecise alias query.
90 const Value *U = GetUnderlyingObjCPtr(V: S);
91 if (U != S)
92 return AAResultBase::getModRefInfoMask(Loc: MemoryLocation::getBeforeOrAfter(Ptr: U),
93 AAQI, IgnoreLocals);
94
95 // If that failed, fail. We don't need to chain here, since that's covered
96 // by the earlier precise query.
97 return ModRefInfo::ModRef;
98}
99
100MemoryEffects ObjCARCAAResult::getMemoryEffects(const Function *F) {
101 if (!EnableARCOpts)
102 return AAResultBase::getMemoryEffects(F);
103
104 switch (GetFunctionClass(F)) {
105 case ARCInstKind::NoopCast:
106 return MemoryEffects::none();
107 default:
108 break;
109 }
110
111 return AAResultBase::getMemoryEffects(F);
112}
113
114ModRefInfo ObjCARCAAResult::getModRefInfo(const CallBase *Call,
115 const MemoryLocation &Loc,
116 AAQueryInfo &AAQI) {
117 if (!EnableARCOpts)
118 return AAResultBase::getModRefInfo(Call, Loc, AAQI);
119
120 switch (GetBasicARCInstKind(V: Call)) {
121 case ARCInstKind::Retain:
122 case ARCInstKind::RetainRV:
123 case ARCInstKind::Autorelease:
124 case ARCInstKind::AutoreleaseRV:
125 case ARCInstKind::NoopCast:
126 case ARCInstKind::AutoreleasepoolPush:
127 case ARCInstKind::FusedRetainAutorelease:
128 case ARCInstKind::FusedRetainAutoreleaseRV:
129 // These functions don't access any memory visible to the compiler.
130 // Note that this doesn't include objc_retainBlock, because it updates
131 // pointers when it copies block data.
132 return ModRefInfo::NoModRef;
133 default:
134 break;
135 }
136
137 return AAResultBase::getModRefInfo(Call, Loc, AAQI);
138}
139
140AnalysisKey ObjCARCAA::Key;
141
142ObjCARCAAResult ObjCARCAA::run(Function &F, FunctionAnalysisManager &AM) {
143 return ObjCARCAAResult(F.getDataLayout());
144}
145