xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric /// This file defines a simple ARC-aware AliasAnalysis using special knowledge
100b57cec5SDimitry Andric /// of Objective C to enhance other optimization passes which rely on the Alias
110b57cec5SDimitry Andric /// Analysis infrastructure.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric /// WARNING: This file knows about certain library functions. It recognizes them
140b57cec5SDimitry Andric /// by name, and hardwires knowledge of their semantics.
150b57cec5SDimitry Andric ///
160b57cec5SDimitry Andric /// WARNING: This file knows about how certain Objective-C library functions are
170b57cec5SDimitry Andric /// used. Naive LLVM IR transformations which would otherwise be
180b57cec5SDimitry Andric /// behavior-preserving may break these assumptions.
190b57cec5SDimitry Andric ///
200b57cec5SDimitry Andric /// TODO: Theoretically we could check for dependencies between objc_* calls
210b57cec5SDimitry Andric /// and FMRB_OnlyAccessesArgumentPointees calls or other well-behaved calls.
220b57cec5SDimitry Andric ///
235f757f3fSDimitry Andric /// TODO: The calls here to AAResultBase member functions are all effectively
245f757f3fSDimitry Andric /// no-ops that just return a conservative result. The original intent was to
255f757f3fSDimitry Andric /// chain to another analysis for a recursive query, but this was lost in a
265f757f3fSDimitry Andric /// refactor. These should instead be rephrased in terms of queries to AAQI.AAR.
275f757f3fSDimitry Andric ///
280b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCAliasAnalysis.h"
310b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
325ffd83dbSDimitry Andric #include "llvm/Analysis/Passes.h"
330b57cec5SDimitry Andric #include "llvm/IR/Function.h"
340b57cec5SDimitry Andric #include "llvm/InitializePasses.h"
355ffd83dbSDimitry Andric #include "llvm/Pass.h"
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-aa"
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace llvm;
400b57cec5SDimitry Andric using namespace llvm::objcarc;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric AliasResult ObjCARCAAResult::alias(const MemoryLocation &LocA,
430b57cec5SDimitry Andric                                    const MemoryLocation &LocB,
44bdd1243dSDimitry Andric                                    AAQueryInfo &AAQI, const Instruction *) {
450b57cec5SDimitry Andric   if (!EnableARCOpts)
46bdd1243dSDimitry Andric     return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   // First, strip off no-ops, including ObjC-specific no-ops, and try making a
490b57cec5SDimitry Andric   // precise alias query.
500b57cec5SDimitry Andric   const Value *SA = GetRCIdentityRoot(LocA.Ptr);
510b57cec5SDimitry Andric   const Value *SB = GetRCIdentityRoot(LocB.Ptr);
52bdd1243dSDimitry Andric   AliasResult Result = AAResultBase::alias(
53bdd1243dSDimitry Andric       MemoryLocation(SA, LocA.Size, LocA.AATags),
54bdd1243dSDimitry Andric       MemoryLocation(SB, LocB.Size, LocB.AATags), AAQI, nullptr);
55fe6060f1SDimitry Andric   if (Result != AliasResult::MayAlias)
560b57cec5SDimitry Andric     return Result;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   // If that failed, climb to the underlying object, including climbing through
590b57cec5SDimitry Andric   // ObjC-specific no-ops, and try making an imprecise alias query.
60e8d8bef9SDimitry Andric   const Value *UA = GetUnderlyingObjCPtr(SA);
61e8d8bef9SDimitry Andric   const Value *UB = GetUnderlyingObjCPtr(SB);
620b57cec5SDimitry Andric   if (UA != SA || UB != SB) {
63e8d8bef9SDimitry Andric     Result = AAResultBase::alias(MemoryLocation::getBeforeOrAfter(UA),
64bdd1243dSDimitry Andric                                  MemoryLocation::getBeforeOrAfter(UB), AAQI,
65bdd1243dSDimitry Andric                                  nullptr);
660b57cec5SDimitry Andric     // We can't use MustAlias or PartialAlias results here because
670b57cec5SDimitry Andric     // GetUnderlyingObjCPtr may return an offsetted pointer value.
68fe6060f1SDimitry Andric     if (Result == AliasResult::NoAlias)
69fe6060f1SDimitry Andric       return AliasResult::NoAlias;
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   // If that failed, fail. We don't need to chain here, since that's covered
730b57cec5SDimitry Andric   // by the earlier precise query.
74fe6060f1SDimitry Andric   return AliasResult::MayAlias;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
77bdd1243dSDimitry Andric ModRefInfo ObjCARCAAResult::getModRefInfoMask(const MemoryLocation &Loc,
78bdd1243dSDimitry Andric                                               AAQueryInfo &AAQI,
79bdd1243dSDimitry Andric                                               bool IgnoreLocals) {
800b57cec5SDimitry Andric   if (!EnableARCOpts)
81bdd1243dSDimitry Andric     return AAResultBase::getModRefInfoMask(Loc, AAQI, IgnoreLocals);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // First, strip off no-ops, including ObjC-specific no-ops, and try making
840b57cec5SDimitry Andric   // a precise alias query.
850b57cec5SDimitry Andric   const Value *S = GetRCIdentityRoot(Loc.Ptr);
86bdd1243dSDimitry Andric   if (isNoModRef(AAResultBase::getModRefInfoMask(
87bdd1243dSDimitry Andric           MemoryLocation(S, Loc.Size, Loc.AATags), AAQI, IgnoreLocals)))
88bdd1243dSDimitry Andric     return ModRefInfo::NoModRef;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   // If that failed, climb to the underlying object, including climbing through
910b57cec5SDimitry Andric   // ObjC-specific no-ops, and try making an imprecise alias query.
92e8d8bef9SDimitry Andric   const Value *U = GetUnderlyingObjCPtr(S);
930b57cec5SDimitry Andric   if (U != S)
94bdd1243dSDimitry Andric     return AAResultBase::getModRefInfoMask(MemoryLocation::getBeforeOrAfter(U),
95bdd1243dSDimitry Andric                                            AAQI, IgnoreLocals);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   // If that failed, fail. We don't need to chain here, since that's covered
980b57cec5SDimitry Andric   // by the earlier precise query.
99bdd1243dSDimitry Andric   return ModRefInfo::ModRef;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
102bdd1243dSDimitry Andric MemoryEffects ObjCARCAAResult::getMemoryEffects(const Function *F) {
1030b57cec5SDimitry Andric   if (!EnableARCOpts)
104bdd1243dSDimitry Andric     return AAResultBase::getMemoryEffects(F);
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   switch (GetFunctionClass(F)) {
1070b57cec5SDimitry Andric   case ARCInstKind::NoopCast:
108bdd1243dSDimitry Andric     return MemoryEffects::none();
1090b57cec5SDimitry Andric   default:
1100b57cec5SDimitry Andric     break;
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric 
113bdd1243dSDimitry Andric   return AAResultBase::getMemoryEffects(F);
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric ModRefInfo ObjCARCAAResult::getModRefInfo(const CallBase *Call,
1170b57cec5SDimitry Andric                                           const MemoryLocation &Loc,
1180b57cec5SDimitry Andric                                           AAQueryInfo &AAQI) {
1190b57cec5SDimitry Andric   if (!EnableARCOpts)
1200b57cec5SDimitry Andric     return AAResultBase::getModRefInfo(Call, Loc, AAQI);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   switch (GetBasicARCInstKind(Call)) {
1230b57cec5SDimitry Andric   case ARCInstKind::Retain:
1240b57cec5SDimitry Andric   case ARCInstKind::RetainRV:
1250b57cec5SDimitry Andric   case ARCInstKind::Autorelease:
1260b57cec5SDimitry Andric   case ARCInstKind::AutoreleaseRV:
1270b57cec5SDimitry Andric   case ARCInstKind::NoopCast:
1280b57cec5SDimitry Andric   case ARCInstKind::AutoreleasepoolPush:
1290b57cec5SDimitry Andric   case ARCInstKind::FusedRetainAutorelease:
1300b57cec5SDimitry Andric   case ARCInstKind::FusedRetainAutoreleaseRV:
1310b57cec5SDimitry Andric     // These functions don't access any memory visible to the compiler.
1320b57cec5SDimitry Andric     // Note that this doesn't include objc_retainBlock, because it updates
1330b57cec5SDimitry Andric     // pointers when it copies block data.
1340b57cec5SDimitry Andric     return ModRefInfo::NoModRef;
1350b57cec5SDimitry Andric   default:
1360b57cec5SDimitry Andric     break;
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   return AAResultBase::getModRefInfo(Call, Loc, AAQI);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
142e8d8bef9SDimitry Andric AnalysisKey ObjCARCAA::Key;
143e8d8bef9SDimitry Andric 
1440b57cec5SDimitry Andric ObjCARCAAResult ObjCARCAA::run(Function &F, FunctionAnalysisManager &AM) {
145*0fca6ea1SDimitry Andric   return ObjCARCAAResult(F.getDataLayout());
1460b57cec5SDimitry Andric }
147