aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/ObjCARC/ObjCARCUtil.cpp
blob: 3192a6df7163092c9ae3038dec12e3f0674c10e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//===- ObjCARCUtil.h - ObjC ARC Optimization ----------*- mode: c++ -*-----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines several utility functions used by various ARC
/// optimizations which are IMHO too big to be in a header file.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//

#include "ObjCARC.h"

using namespace llvm;
using namespace llvm::objcarc;

raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS,
                                       const InstructionClass Class) {
  switch (Class) {
  case IC_Retain:
    return OS << "IC_Retain";
  case IC_RetainRV:
    return OS << "IC_RetainRV";
  case IC_RetainBlock:
    return OS << "IC_RetainBlock";
  case IC_Release:
    return OS << "IC_Release";
  case IC_Autorelease:
    return OS << "IC_Autorelease";
  case IC_AutoreleaseRV:
    return OS << "IC_AutoreleaseRV";
  case IC_AutoreleasepoolPush:
    return OS << "IC_AutoreleasepoolPush";
  case IC_AutoreleasepoolPop:
    return OS << "IC_AutoreleasepoolPop";
  case IC_NoopCast:
    return OS << "IC_NoopCast";
  case IC_FusedRetainAutorelease:
    return OS << "IC_FusedRetainAutorelease";
  case IC_FusedRetainAutoreleaseRV:
    return OS << "IC_FusedRetainAutoreleaseRV";
  case IC_LoadWeakRetained:
    return OS << "IC_LoadWeakRetained";
  case IC_StoreWeak:
    return OS << "IC_StoreWeak";
  case IC_InitWeak:
    return OS << "IC_InitWeak";
  case IC_LoadWeak:
    return OS << "IC_LoadWeak";
  case IC_MoveWeak:
    return OS << "IC_MoveWeak";
  case IC_CopyWeak:
    return OS << "IC_CopyWeak";
  case IC_DestroyWeak:
    return OS << "IC_DestroyWeak";
  case IC_StoreStrong:
    return OS << "IC_StoreStrong";
  case IC_CallOrUser:
    return OS << "IC_CallOrUser";
  case IC_Call:
    return OS << "IC_Call";
  case IC_User:
    return OS << "IC_User";
  case IC_None:
    return OS << "IC_None";
  }
  llvm_unreachable("Unknown instruction class!");
}

InstructionClass llvm::objcarc::GetFunctionClass(const Function *F) {
  Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();

  // No arguments.
  if (AI == AE)
    return StringSwitch<InstructionClass>(F->getName())
      .Case("objc_autoreleasePoolPush",  IC_AutoreleasepoolPush)
      .Default(IC_CallOrUser);

  // One argument.
  const Argument *A0 = AI++;
  if (AI == AE)
    // Argument is a pointer.
    if (PointerType *PTy = dyn_cast<PointerType>(A0->getType())) {
      Type *ETy = PTy->getElementType();
      // Argument is i8*.
      if (ETy->isIntegerTy(8))
        return StringSwitch<InstructionClass>(F->getName())
          .Case("objc_retain",                IC_Retain)
          .Case("objc_retainAutoreleasedReturnValue", IC_RetainRV)
          .Case("objc_retainBlock",           IC_RetainBlock)
          .Case("objc_release",               IC_Release)
          .Case("objc_autorelease",           IC_Autorelease)
          .Case("objc_autoreleaseReturnValue", IC_AutoreleaseRV)
          .Case("objc_autoreleasePoolPop",    IC_AutoreleasepoolPop)
          .Case("objc_retainedObject",        IC_NoopCast)
          .Case("objc_unretainedObject",      IC_NoopCast)
          .Case("objc_unretainedPointer",     IC_NoopCast)
          .Case("objc_retain_autorelease",    IC_FusedRetainAutorelease)
          .Case("objc_retainAutorelease",     IC_FusedRetainAutorelease)
          .Case("objc_retainAutoreleaseReturnValue",IC_FusedRetainAutoreleaseRV)
          .Default(IC_CallOrUser);

      // Argument is i8**
      if (PointerType *Pte = dyn_cast<PointerType>(ETy))
        if (Pte->getElementType()->isIntegerTy(8))
          return StringSwitch<InstructionClass>(F->getName())
            .Case("objc_loadWeakRetained",      IC_LoadWeakRetained)
            .Case("objc_loadWeak",              IC_LoadWeak)
            .Case("objc_destroyWeak",           IC_DestroyWeak)
            .Default(IC_CallOrUser);
    }

  // Two arguments, first is i8**.
  const Argument *A1 = AI++;
  if (AI == AE)
    if (PointerType *PTy = dyn_cast<PointerType>(A0->getType()))
      if (PointerType *Pte = dyn_cast<PointerType>(PTy->getElementType()))
        if (Pte->getElementType()->isIntegerTy(8))
          if (PointerType *PTy1 = dyn_cast<PointerType>(A1->getType())) {
            Type *ETy1 = PTy1->getElementType();
            // Second argument is i8*
            if (ETy1->isIntegerTy(8))
              return StringSwitch<InstructionClass>(F->getName())
                .Case("objc_storeWeak",             IC_StoreWeak)
                .Case("objc_initWeak",              IC_InitWeak)
                .Case("objc_storeStrong",           IC_StoreStrong)
                .Default(IC_CallOrUser);
            // Second argument is i8**.
            if (PointerType *Pte1 = dyn_cast<PointerType>(ETy1))
              if (Pte1->getElementType()->isIntegerTy(8))
                return StringSwitch<InstructionClass>(F->getName())
                  .Case("objc_moveWeak",              IC_MoveWeak)
                  .Case("objc_copyWeak",              IC_CopyWeak)
                  .Default(IC_CallOrUser);
          }

  // Anything else.
  return IC_CallOrUser;
}