1//===- ARCRuntimeEntryPoints.h - ObjC ARC Optimization --*- C++ -*---------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9/// \file
10/// This file contains a class ARCRuntimeEntryPoints for use in
11/// creating/managing references to entry points to the arc objective c runtime.
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//===----------------------------------------------------------------------===//
21
22#ifndef LLVM_TRANSFORMS_SCALAR_ARCRUNTIMEENTRYPOINTS_H
23#define LLVM_TRANSFORMS_SCALAR_ARCRUNTIMEENTRYPOINTS_H
24
25#include "ObjCARC.h"
26
27namespace llvm {
28namespace objcarc {
29
30/// Declarations for ObjC runtime functions and constants. These are initialized
31/// lazily to avoid cluttering up the Module with unused declarations.
32class ARCRuntimeEntryPoints {
33public:
34  enum EntryPointType {
35    EPT_AutoreleaseRV,
36    EPT_Release,
37    EPT_Retain,
38    EPT_RetainBlock,
39    EPT_Autorelease,
40    EPT_StoreStrong,
41    EPT_RetainRV,
42    EPT_RetainAutorelease,
43    EPT_RetainAutoreleaseRV
44  };
45
46  ARCRuntimeEntryPoints() : TheModule(nullptr),
47                            AutoreleaseRV(nullptr),
48                            Release(nullptr),
49                            Retain(nullptr),
50                            RetainBlock(nullptr),
51                            Autorelease(nullptr),
52                            StoreStrong(nullptr),
53                            RetainRV(nullptr),
54                            RetainAutorelease(nullptr),
55                            RetainAutoreleaseRV(nullptr) { }
56
57  ~ARCRuntimeEntryPoints() { }
58
59  void Initialize(Module *M) {
60    TheModule = M;
61    AutoreleaseRV = nullptr;
62    Release = nullptr;
63    Retain = nullptr;
64    RetainBlock = nullptr;
65    Autorelease = nullptr;
66    StoreStrong = nullptr;
67    RetainRV = nullptr;
68    RetainAutorelease = nullptr;
69    RetainAutoreleaseRV = nullptr;
70  }
71
72  Constant *get(const EntryPointType entry) {
73    assert(TheModule != nullptr && "Not initialized.");
74
75    switch (entry) {
76    case EPT_AutoreleaseRV:
77      return getI8XRetI8XEntryPoint(AutoreleaseRV,
78                                    "objc_autoreleaseReturnValue", true);
79    case EPT_Release:
80      return getVoidRetI8XEntryPoint(Release, "objc_release");
81    case EPT_Retain:
82      return getI8XRetI8XEntryPoint(Retain, "objc_retain", true);
83    case EPT_RetainBlock:
84      return getI8XRetI8XEntryPoint(RetainBlock, "objc_retainBlock", false);
85    case EPT_Autorelease:
86      return getI8XRetI8XEntryPoint(Autorelease, "objc_autorelease", true);
87    case EPT_StoreStrong:
88      return getI8XRetI8XXI8XEntryPoint(StoreStrong, "objc_storeStrong");
89    case EPT_RetainRV:
90      return getI8XRetI8XEntryPoint(RetainRV,
91                                    "objc_retainAutoreleasedReturnValue", true);
92    case EPT_RetainAutorelease:
93      return getI8XRetI8XEntryPoint(RetainAutorelease, "objc_retainAutorelease",
94                                    true);
95    case EPT_RetainAutoreleaseRV:
96      return getI8XRetI8XEntryPoint(RetainAutoreleaseRV,
97                                    "objc_retainAutoreleaseReturnValue", true);
98    }
99
100    llvm_unreachable("Switch should be a covered switch.");
101  }
102
103private:
104  /// Cached reference to the module which we will insert declarations into.
105  Module *TheModule;
106
107  /// Declaration for ObjC runtime function objc_autoreleaseReturnValue.
108  Constant *AutoreleaseRV;
109  /// Declaration for ObjC runtime function objc_release.
110  Constant *Release;
111  /// Declaration for ObjC runtime function objc_retain.
112  Constant *Retain;
113  /// Declaration for ObjC runtime function objc_retainBlock.
114  Constant *RetainBlock;
115  /// Declaration for ObjC runtime function objc_autorelease.
116  Constant *Autorelease;
117  /// Declaration for objc_storeStrong().
118  Constant *StoreStrong;
119  /// Declaration for objc_retainAutoreleasedReturnValue().
120  Constant *RetainRV;
121  /// Declaration for objc_retainAutorelease().
122  Constant *RetainAutorelease;
123  /// Declaration for objc_retainAutoreleaseReturnValue().
124  Constant *RetainAutoreleaseRV;
125
126  Constant *getVoidRetI8XEntryPoint(Constant *&Decl,
127                                    const char *Name) {
128    if (Decl)
129      return Decl;
130
131    LLVMContext &C = TheModule->getContext();
132    Type *Params[] = { PointerType::getUnqual(Type::getInt8Ty(C)) };
133    AttributeSet Attr =
134      AttributeSet().addAttribute(C, AttributeSet::FunctionIndex,
135                                  Attribute::NoUnwind);
136    FunctionType *Fty = FunctionType::get(Type::getVoidTy(C), Params,
137                                          /*isVarArg=*/false);
138    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
139  }
140
141  Constant *getI8XRetI8XEntryPoint(Constant *& Decl,
142                                   const char *Name,
143                                   bool NoUnwind = false) {
144    if (Decl)
145      return Decl;
146
147    LLVMContext &C = TheModule->getContext();
148    Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
149    Type *Params[] = { I8X };
150    FunctionType *Fty = FunctionType::get(I8X, Params, /*isVarArg=*/false);
151    AttributeSet Attr = AttributeSet();
152
153    if (NoUnwind)
154      Attr = Attr.addAttribute(C, AttributeSet::FunctionIndex,
155                               Attribute::NoUnwind);
156
157    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
158  }
159
160  Constant *getI8XRetI8XXI8XEntryPoint(Constant *&Decl,
161                                       const char *Name) {
162    if (Decl)
163      return Decl;
164
165    LLVMContext &C = TheModule->getContext();
166    Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
167    Type *I8XX = PointerType::getUnqual(I8X);
168    Type *Params[] = { I8XX, I8X };
169
170    AttributeSet Attr =
171      AttributeSet().addAttribute(C, AttributeSet::FunctionIndex,
172                                  Attribute::NoUnwind);
173    Attr = Attr.addAttribute(C, 1, Attribute::NoCapture);
174
175    FunctionType *Fty = FunctionType::get(Type::getVoidTy(C), Params,
176                                          /*isVarArg=*/false);
177
178    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
179  }
180
181}; // class ARCRuntimeEntryPoints
182
183} // namespace objcarc
184} // namespace llvm
185
186#endif // LLVM_TRANSFORMS_SCALAR_ARCRUNTIMEENTRYPOINTS_H
187