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/Analysis/Passes.h" |
33 | #include "llvm/IR/Function.h" |
34 | #include "llvm/InitializePasses.h" |
35 | #include "llvm/Pass.h" |
36 | |
37 | #define DEBUG_TYPE "objc-arc-aa" |
38 | |
39 | using namespace llvm; |
40 | using namespace llvm::objcarc; |
41 | |
42 | AliasResult ObjCARCAAResult::alias(const MemoryLocation &LocA, |
43 | const MemoryLocation &LocB, |
44 | AAQueryInfo &AAQI, const Instruction *) { |
45 | if (!EnableARCOpts) |
46 | return AAResultBase::alias(LocA, LocB, AAQI, I: nullptr); |
47 | |
48 | // First, strip off no-ops, including ObjC-specific no-ops, and try making a |
49 | // precise alias query. |
50 | const Value *SA = GetRCIdentityRoot(V: LocA.Ptr); |
51 | const Value *SB = GetRCIdentityRoot(V: LocB.Ptr); |
52 | AliasResult Result = AAResultBase::alias( |
53 | LocA: MemoryLocation(SA, LocA.Size, LocA.AATags), |
54 | LocB: MemoryLocation(SB, LocB.Size, LocB.AATags), AAQI, I: nullptr); |
55 | if (Result != AliasResult::MayAlias) |
56 | return Result; |
57 | |
58 | // If that failed, climb to the underlying object, including climbing through |
59 | // ObjC-specific no-ops, and try making an imprecise alias query. |
60 | const Value *UA = GetUnderlyingObjCPtr(V: SA); |
61 | const Value *UB = GetUnderlyingObjCPtr(V: SB); |
62 | if (UA != SA || UB != SB) { |
63 | Result = AAResultBase::alias(LocA: MemoryLocation::getBeforeOrAfter(Ptr: UA), |
64 | LocB: MemoryLocation::getBeforeOrAfter(Ptr: UB), AAQI, |
65 | I: nullptr); |
66 | // We can't use MustAlias or PartialAlias results here because |
67 | // GetUnderlyingObjCPtr may return an offsetted pointer value. |
68 | if (Result == AliasResult::NoAlias) |
69 | return AliasResult::NoAlias; |
70 | } |
71 | |
72 | // If that failed, fail. We don't need to chain here, since that's covered |
73 | // by the earlier precise query. |
74 | return AliasResult::MayAlias; |
75 | } |
76 | |
77 | ModRefInfo ObjCARCAAResult::getModRefInfoMask(const MemoryLocation &Loc, |
78 | AAQueryInfo &AAQI, |
79 | bool IgnoreLocals) { |
80 | if (!EnableARCOpts) |
81 | return AAResultBase::getModRefInfoMask(Loc, AAQI, IgnoreLocals); |
82 | |
83 | // First, strip off no-ops, including ObjC-specific no-ops, and try making |
84 | // a precise alias query. |
85 | const Value *S = GetRCIdentityRoot(V: Loc.Ptr); |
86 | if (isNoModRef(MRI: AAResultBase::getModRefInfoMask( |
87 | Loc: MemoryLocation(S, Loc.Size, Loc.AATags), AAQI, IgnoreLocals))) |
88 | return ModRefInfo::NoModRef; |
89 | |
90 | // If that failed, climb to the underlying object, including climbing through |
91 | // ObjC-specific no-ops, and try making an imprecise alias query. |
92 | const Value *U = GetUnderlyingObjCPtr(V: S); |
93 | if (U != S) |
94 | return AAResultBase::getModRefInfoMask(Loc: MemoryLocation::getBeforeOrAfter(Ptr: U), |
95 | AAQI, IgnoreLocals); |
96 | |
97 | // If that failed, fail. We don't need to chain here, since that's covered |
98 | // by the earlier precise query. |
99 | return ModRefInfo::ModRef; |
100 | } |
101 | |
102 | MemoryEffects ObjCARCAAResult::getMemoryEffects(const Function *F) { |
103 | if (!EnableARCOpts) |
104 | return AAResultBase::getMemoryEffects(F); |
105 | |
106 | switch (GetFunctionClass(F)) { |
107 | case ARCInstKind::NoopCast: |
108 | return MemoryEffects::none(); |
109 | default: |
110 | break; |
111 | } |
112 | |
113 | return AAResultBase::getMemoryEffects(F); |
114 | } |
115 | |
116 | ModRefInfo ObjCARCAAResult::getModRefInfo(const CallBase *Call, |
117 | const MemoryLocation &Loc, |
118 | AAQueryInfo &AAQI) { |
119 | if (!EnableARCOpts) |
120 | return AAResultBase::getModRefInfo(Call, Loc, AAQI); |
121 | |
122 | switch (GetBasicARCInstKind(V: Call)) { |
123 | case ARCInstKind::Retain: |
124 | case ARCInstKind::RetainRV: |
125 | case ARCInstKind::Autorelease: |
126 | case ARCInstKind::AutoreleaseRV: |
127 | case ARCInstKind::NoopCast: |
128 | case ARCInstKind::AutoreleasepoolPush: |
129 | case ARCInstKind::FusedRetainAutorelease: |
130 | case ARCInstKind::FusedRetainAutoreleaseRV: |
131 | // These functions don't access any memory visible to the compiler. |
132 | // Note that this doesn't include objc_retainBlock, because it updates |
133 | // pointers when it copies block data. |
134 | return ModRefInfo::NoModRef; |
135 | default: |
136 | break; |
137 | } |
138 | |
139 | return AAResultBase::getModRefInfo(Call, Loc, AAQI); |
140 | } |
141 | |
142 | AnalysisKey ObjCARCAA::Key; |
143 | |
144 | ObjCARCAAResult ObjCARCAA::run(Function &F, FunctionAnalysisManager &AM) { |
145 | return ObjCARCAAResult(F.getDataLayout()); |
146 | } |
147 | |