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