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_LIB_TRANSFORMS_OBJCARC_ARCRUNTIMEENTRYPOINTS_H
23#define LLVM_LIB_TRANSFORMS_OBJCARC_ARCRUNTIMEENTRYPOINTS_H
24
25#include "ObjCARC.h"
26
27namespace llvm {
28namespace objcarc {
29
30enum class ARCRuntimeEntryPointKind {
31  AutoreleaseRV,
32  Release,
33  Retain,
34  RetainBlock,
35  Autorelease,
36  StoreStrong,
37  RetainRV,
38  RetainAutorelease,
39  RetainAutoreleaseRV,
40};
41
42/// Declarations for ObjC runtime functions and constants. These are initialized
43/// lazily to avoid cluttering up the Module with unused declarations.
44class ARCRuntimeEntryPoints {
45public:
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  void init(Module *M) {
58    TheModule = M;
59    AutoreleaseRV = nullptr;
60    Release = nullptr;
61    Retain = nullptr;
62    RetainBlock = nullptr;
63    Autorelease = nullptr;
64    StoreStrong = nullptr;
65    RetainRV = nullptr;
66    RetainAutorelease = nullptr;
67    RetainAutoreleaseRV = nullptr;
68  }
69
70  Constant *get(ARCRuntimeEntryPointKind kind) {
71    assert(TheModule != nullptr && "Not initialized.");
72
73    switch (kind) {
74    case ARCRuntimeEntryPointKind::AutoreleaseRV:
75      return getI8XRetI8XEntryPoint(AutoreleaseRV,
76                                    "objc_autoreleaseReturnValue", true);
77    case ARCRuntimeEntryPointKind::Release:
78      return getVoidRetI8XEntryPoint(Release, "objc_release");
79    case ARCRuntimeEntryPointKind::Retain:
80      return getI8XRetI8XEntryPoint(Retain, "objc_retain", true);
81    case ARCRuntimeEntryPointKind::RetainBlock:
82      return getI8XRetI8XEntryPoint(RetainBlock, "objc_retainBlock", false);
83    case ARCRuntimeEntryPointKind::Autorelease:
84      return getI8XRetI8XEntryPoint(Autorelease, "objc_autorelease", true);
85    case ARCRuntimeEntryPointKind::StoreStrong:
86      return getI8XRetI8XXI8XEntryPoint(StoreStrong, "objc_storeStrong");
87    case ARCRuntimeEntryPointKind::RetainRV:
88      return getI8XRetI8XEntryPoint(RetainRV,
89                                    "objc_retainAutoreleasedReturnValue", true);
90    case ARCRuntimeEntryPointKind::RetainAutorelease:
91      return getI8XRetI8XEntryPoint(RetainAutorelease, "objc_retainAutorelease",
92                                    true);
93    case ARCRuntimeEntryPointKind::RetainAutoreleaseRV:
94      return getI8XRetI8XEntryPoint(RetainAutoreleaseRV,
95                                    "objc_retainAutoreleaseReturnValue", true);
96    }
97
98    llvm_unreachable("Switch should be a covered switch.");
99  }
100
101private:
102  /// Cached reference to the module which we will insert declarations into.
103  Module *TheModule;
104
105  /// Declaration for ObjC runtime function objc_autoreleaseReturnValue.
106  Constant *AutoreleaseRV;
107  /// Declaration for ObjC runtime function objc_release.
108  Constant *Release;
109  /// Declaration for ObjC runtime function objc_retain.
110  Constant *Retain;
111  /// Declaration for ObjC runtime function objc_retainBlock.
112  Constant *RetainBlock;
113  /// Declaration for ObjC runtime function objc_autorelease.
114  Constant *Autorelease;
115  /// Declaration for objc_storeStrong().
116  Constant *StoreStrong;
117  /// Declaration for objc_retainAutoreleasedReturnValue().
118  Constant *RetainRV;
119  /// Declaration for objc_retainAutorelease().
120  Constant *RetainAutorelease;
121  /// Declaration for objc_retainAutoreleaseReturnValue().
122  Constant *RetainAutoreleaseRV;
123
124  Constant *getVoidRetI8XEntryPoint(Constant *&Decl,
125                                    const char *Name) {
126    if (Decl)
127      return Decl;
128
129    LLVMContext &C = TheModule->getContext();
130    Type *Params[] = { PointerType::getUnqual(Type::getInt8Ty(C)) };
131    AttributeSet Attr =
132      AttributeSet().addAttribute(C, AttributeSet::FunctionIndex,
133                                  Attribute::NoUnwind);
134    FunctionType *Fty = FunctionType::get(Type::getVoidTy(C), Params,
135                                          /*isVarArg=*/false);
136    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
137  }
138
139  Constant *getI8XRetI8XEntryPoint(Constant *& Decl,
140                                   const char *Name,
141                                   bool NoUnwind = false) {
142    if (Decl)
143      return Decl;
144
145    LLVMContext &C = TheModule->getContext();
146    Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
147    Type *Params[] = { I8X };
148    FunctionType *Fty = FunctionType::get(I8X, Params, /*isVarArg=*/false);
149    AttributeSet Attr = AttributeSet();
150
151    if (NoUnwind)
152      Attr = Attr.addAttribute(C, AttributeSet::FunctionIndex,
153                               Attribute::NoUnwind);
154
155    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
156  }
157
158  Constant *getI8XRetI8XXI8XEntryPoint(Constant *&Decl,
159                                       const char *Name) {
160    if (Decl)
161      return Decl;
162
163    LLVMContext &C = TheModule->getContext();
164    Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
165    Type *I8XX = PointerType::getUnqual(I8X);
166    Type *Params[] = { I8XX, I8X };
167
168    AttributeSet Attr =
169      AttributeSet().addAttribute(C, AttributeSet::FunctionIndex,
170                                  Attribute::NoUnwind);
171    Attr = Attr.addAttribute(C, 1, Attribute::NoCapture);
172
173    FunctionType *Fty = FunctionType::get(Type::getVoidTy(C), Params,
174                                          /*isVarArg=*/false);
175
176    return Decl = TheModule->getOrInsertFunction(Name, Fty, Attr);
177  }
178
179}; // class ARCRuntimeEntryPoints
180
181} // namespace objcarc
182} // namespace llvm
183
184#endif
185