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 
27 namespace llvm {
28 namespace objcarc {
29 
30 enum 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.
44 class ARCRuntimeEntryPoints {
45 public:
ARCRuntimeEntryPoints()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 
init(Module * M)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 
get(ARCRuntimeEntryPointKind kind)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 
101 private:
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 
getVoidRetI8XEntryPoint(Constant * & Decl,const char * Name)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 
getI8XRetI8XXI8XEntryPoint(Constant * & Decl,const char * Name)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