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, 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(LocA.Ptr); 51 const Value *SB = GetRCIdentityRoot(LocB.Ptr); 52 AliasResult Result = AAResultBase::alias( 53 MemoryLocation(SA, LocA.Size, LocA.AATags), 54 MemoryLocation(SB, LocB.Size, LocB.AATags), AAQI, 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(SA); 61 const Value *UB = GetUnderlyingObjCPtr(SB); 62 if (UA != SA || UB != SB) { 63 Result = AAResultBase::alias(MemoryLocation::getBeforeOrAfter(UA), 64 MemoryLocation::getBeforeOrAfter(UB), AAQI, 65 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(Loc.Ptr); 86 if (isNoModRef(AAResultBase::getModRefInfoMask( 87 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(S); 93 if (U != S) 94 return AAResultBase::getModRefInfoMask(MemoryLocation::getBeforeOrAfter(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(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.getParent()->getDataLayout()); 146 } 147