1263508Sdim//===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim/// \file
10249259Sdim/// This file defines a simple ARC-aware AliasAnalysis using special knowledge
11249259Sdim/// of Objective C to enhance other optimization passes which rely on the Alias
12249259Sdim/// Analysis infrastructure.
13249259Sdim///
14249259Sdim/// WARNING: This file knows about certain library functions. It recognizes them
15249259Sdim/// by name, and hardwires knowledge of their semantics.
16249259Sdim///
17249259Sdim/// WARNING: This file knows about how certain Objective-C library functions are
18249259Sdim/// used. Naive LLVM IR transformations which would otherwise be
19249259Sdim/// behavior-preserving may break these assumptions.
20249259Sdim///
21249259Sdim//===----------------------------------------------------------------------===//
22249259Sdim
23249259Sdim#define DEBUG_TYPE "objc-arc-aa"
24249259Sdim#include "ObjCARC.h"
25249259Sdim#include "ObjCARCAliasAnalysis.h"
26249259Sdim#include "llvm/IR/Instruction.h"
27249259Sdim#include "llvm/InitializePasses.h"
28249259Sdim#include "llvm/PassAnalysisSupport.h"
29249259Sdim#include "llvm/PassSupport.h"
30249259Sdim
31249259Sdimnamespace llvm {
32249259Sdim  class Function;
33249259Sdim  class Value;
34249259Sdim}
35249259Sdim
36249259Sdimusing namespace llvm;
37249259Sdimusing namespace llvm::objcarc;
38249259Sdim
39249259Sdim// Register this pass...
40249259Sdimchar ObjCARCAliasAnalysis::ID = 0;
41249259SdimINITIALIZE_AG_PASS(ObjCARCAliasAnalysis, AliasAnalysis, "objc-arc-aa",
42249259Sdim                   "ObjC-ARC-Based Alias Analysis", false, true, false)
43249259Sdim
44249259SdimImmutablePass *llvm::createObjCARCAliasAnalysisPass() {
45249259Sdim  return new ObjCARCAliasAnalysis();
46249259Sdim}
47249259Sdim
48249259Sdimvoid
49249259SdimObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
50249259Sdim  AU.setPreservesAll();
51249259Sdim  AliasAnalysis::getAnalysisUsage(AU);
52249259Sdim}
53249259Sdim
54249259SdimAliasAnalysis::AliasResult
55249259SdimObjCARCAliasAnalysis::alias(const Location &LocA, const Location &LocB) {
56249259Sdim  if (!EnableARCOpts)
57249259Sdim    return AliasAnalysis::alias(LocA, LocB);
58249259Sdim
59249259Sdim  // First, strip off no-ops, including ObjC-specific no-ops, and try making a
60249259Sdim  // precise alias query.
61249259Sdim  const Value *SA = StripPointerCastsAndObjCCalls(LocA.Ptr);
62249259Sdim  const Value *SB = StripPointerCastsAndObjCCalls(LocB.Ptr);
63249259Sdim  AliasResult Result =
64249259Sdim    AliasAnalysis::alias(Location(SA, LocA.Size, LocA.TBAATag),
65249259Sdim                         Location(SB, LocB.Size, LocB.TBAATag));
66249259Sdim  if (Result != MayAlias)
67249259Sdim    return Result;
68249259Sdim
69249259Sdim  // If that failed, climb to the underlying object, including climbing through
70249259Sdim  // ObjC-specific no-ops, and try making an imprecise alias query.
71249259Sdim  const Value *UA = GetUnderlyingObjCPtr(SA);
72249259Sdim  const Value *UB = GetUnderlyingObjCPtr(SB);
73249259Sdim  if (UA != SA || UB != SB) {
74249259Sdim    Result = AliasAnalysis::alias(Location(UA), Location(UB));
75249259Sdim    // We can't use MustAlias or PartialAlias results here because
76249259Sdim    // GetUnderlyingObjCPtr may return an offsetted pointer value.
77249259Sdim    if (Result == NoAlias)
78249259Sdim      return NoAlias;
79249259Sdim  }
80249259Sdim
81249259Sdim  // If that failed, fail. We don't need to chain here, since that's covered
82249259Sdim  // by the earlier precise query.
83249259Sdim  return MayAlias;
84249259Sdim}
85249259Sdim
86249259Sdimbool
87249259SdimObjCARCAliasAnalysis::pointsToConstantMemory(const Location &Loc,
88249259Sdim                                             bool OrLocal) {
89249259Sdim  if (!EnableARCOpts)
90249259Sdim    return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal);
91249259Sdim
92249259Sdim  // First, strip off no-ops, including ObjC-specific no-ops, and try making
93249259Sdim  // a precise alias query.
94249259Sdim  const Value *S = StripPointerCastsAndObjCCalls(Loc.Ptr);
95249259Sdim  if (AliasAnalysis::pointsToConstantMemory(Location(S, Loc.Size, Loc.TBAATag),
96249259Sdim                                            OrLocal))
97249259Sdim    return true;
98249259Sdim
99249259Sdim  // If that failed, climb to the underlying object, including climbing through
100249259Sdim  // ObjC-specific no-ops, and try making an imprecise alias query.
101249259Sdim  const Value *U = GetUnderlyingObjCPtr(S);
102249259Sdim  if (U != S)
103249259Sdim    return AliasAnalysis::pointsToConstantMemory(Location(U), OrLocal);
104249259Sdim
105249259Sdim  // If that failed, fail. We don't need to chain here, since that's covered
106249259Sdim  // by the earlier precise query.
107249259Sdim  return false;
108249259Sdim}
109249259Sdim
110249259SdimAliasAnalysis::ModRefBehavior
111249259SdimObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
112249259Sdim  // We have nothing to do. Just chain to the next AliasAnalysis.
113249259Sdim  return AliasAnalysis::getModRefBehavior(CS);
114249259Sdim}
115249259Sdim
116249259SdimAliasAnalysis::ModRefBehavior
117249259SdimObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
118249259Sdim  if (!EnableARCOpts)
119249259Sdim    return AliasAnalysis::getModRefBehavior(F);
120249259Sdim
121249259Sdim  switch (GetFunctionClass(F)) {
122249259Sdim  case IC_NoopCast:
123249259Sdim    return DoesNotAccessMemory;
124249259Sdim  default:
125249259Sdim    break;
126249259Sdim  }
127249259Sdim
128249259Sdim  return AliasAnalysis::getModRefBehavior(F);
129249259Sdim}
130249259Sdim
131249259SdimAliasAnalysis::ModRefResult
132249259SdimObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS, const Location &Loc) {
133249259Sdim  if (!EnableARCOpts)
134249259Sdim    return AliasAnalysis::getModRefInfo(CS, Loc);
135249259Sdim
136249259Sdim  switch (GetBasicInstructionClass(CS.getInstruction())) {
137249259Sdim  case IC_Retain:
138249259Sdim  case IC_RetainRV:
139249259Sdim  case IC_Autorelease:
140249259Sdim  case IC_AutoreleaseRV:
141249259Sdim  case IC_NoopCast:
142249259Sdim  case IC_AutoreleasepoolPush:
143249259Sdim  case IC_FusedRetainAutorelease:
144249259Sdim  case IC_FusedRetainAutoreleaseRV:
145249259Sdim    // These functions don't access any memory visible to the compiler.
146249259Sdim    // Note that this doesn't include objc_retainBlock, because it updates
147249259Sdim    // pointers when it copies block data.
148249259Sdim    return NoModRef;
149249259Sdim  default:
150249259Sdim    break;
151249259Sdim  }
152249259Sdim
153249259Sdim  return AliasAnalysis::getModRefInfo(CS, Loc);
154249259Sdim}
155249259Sdim
156249259SdimAliasAnalysis::ModRefResult
157249259SdimObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1,
158249259Sdim                                    ImmutableCallSite CS2) {
159249259Sdim  // TODO: Theoretically we could check for dependencies between objc_* calls
160249259Sdim  // and OnlyAccessesArgumentPointees calls or other well-behaved calls.
161249259Sdim  return AliasAnalysis::getModRefInfo(CS1, CS2);
162249259Sdim}
163