1 | //===- ObjCARCInstKind.h - ARC instruction equivalence classes --*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_ANALYSIS_OBJCARCINSTKIND_H |
10 | #define LLVM_ANALYSIS_OBJCARCINSTKIND_H |
11 | |
12 | #include "llvm/IR/Instructions.h" |
13 | |
14 | namespace llvm { |
15 | namespace objcarc { |
16 | |
17 | /// \enum ARCInstKind |
18 | /// |
19 | /// Equivalence classes of instructions in the ARC Model. |
20 | /// |
21 | /// Since we do not have "instructions" to represent ARC concepts in LLVM IR, |
22 | /// we instead operate on equivalence classes of instructions. |
23 | /// |
24 | /// TODO: This should be split into two enums: a runtime entry point enum |
25 | /// (possibly united with the ARCRuntimeEntrypoint class) and an enum that deals |
26 | /// with effects of instructions in the ARC model (which would handle the notion |
27 | /// of a User or CallOrUser). |
28 | enum class ARCInstKind { |
29 | Retain, ///< objc_retain |
30 | RetainRV, ///< objc_retainAutoreleasedReturnValue |
31 | UnsafeClaimRV, ///< objc_unsafeClaimAutoreleasedReturnValue |
32 | RetainBlock, ///< objc_retainBlock |
33 | Release, ///< objc_release |
34 | Autorelease, ///< objc_autorelease |
35 | AutoreleaseRV, ///< objc_autoreleaseReturnValue |
36 | AutoreleasepoolPush, ///< objc_autoreleasePoolPush |
37 | AutoreleasepoolPop, ///< objc_autoreleasePoolPop |
38 | NoopCast, ///< objc_retainedObject, etc. |
39 | FusedRetainAutorelease, ///< objc_retainAutorelease |
40 | FusedRetainAutoreleaseRV, ///< objc_retainAutoreleaseReturnValue |
41 | LoadWeakRetained, ///< objc_loadWeakRetained (primitive) |
42 | StoreWeak, ///< objc_storeWeak (primitive) |
43 | InitWeak, ///< objc_initWeak (derived) |
44 | LoadWeak, ///< objc_loadWeak (derived) |
45 | MoveWeak, ///< objc_moveWeak (derived) |
46 | CopyWeak, ///< objc_copyWeak (derived) |
47 | DestroyWeak, ///< objc_destroyWeak (derived) |
48 | StoreStrong, ///< objc_storeStrong (derived) |
49 | IntrinsicUser, ///< llvm.objc.clang.arc.use |
50 | CallOrUser, ///< could call objc_release and/or "use" pointers |
51 | Call, ///< could call objc_release |
52 | User, ///< could "use" a pointer |
53 | None ///< anything that is inert from an ARC perspective. |
54 | }; |
55 | |
56 | raw_ostream &operator<<(raw_ostream &OS, const ARCInstKind Class); |
57 | |
58 | /// Test if the given class is a kind of user. |
59 | bool IsUser(ARCInstKind Class); |
60 | |
61 | /// Test if the given class is objc_retain or equivalent. |
62 | bool IsRetain(ARCInstKind Class); |
63 | |
64 | /// Test if the given class is objc_autorelease or equivalent. |
65 | bool IsAutorelease(ARCInstKind Class); |
66 | |
67 | /// Test if the given class represents instructions which return their |
68 | /// argument verbatim. |
69 | bool IsForwarding(ARCInstKind Class); |
70 | |
71 | /// Test if the given class represents instructions which do nothing if |
72 | /// passed a null pointer. |
73 | bool IsNoopOnNull(ARCInstKind Class); |
74 | |
75 | /// Test if the given class represents instructions which do nothing if |
76 | /// passed a global variable. |
77 | bool IsNoopOnGlobal(ARCInstKind Class); |
78 | |
79 | /// Test if the given class represents instructions which are always safe |
80 | /// to mark with the "tail" keyword. |
81 | bool IsAlwaysTail(ARCInstKind Class); |
82 | |
83 | /// Test if the given class represents instructions which are never safe |
84 | /// to mark with the "tail" keyword. |
85 | bool IsNeverTail(ARCInstKind Class); |
86 | |
87 | /// Test if the given class represents instructions which are always safe |
88 | /// to mark with the nounwind attribute. |
89 | bool IsNoThrow(ARCInstKind Class); |
90 | |
91 | /// Test whether the given instruction can autorelease any pointer or cause an |
92 | /// autoreleasepool pop. |
93 | bool CanInterruptRV(ARCInstKind Class); |
94 | |
95 | /// Determine if F is one of the special known Functions. If it isn't, |
96 | /// return ARCInstKind::CallOrUser. |
97 | ARCInstKind GetFunctionClass(const Function *F); |
98 | |
99 | /// Determine which objc runtime call instruction class V belongs to. |
100 | /// |
101 | /// This is similar to GetARCInstKind except that it only detects objc |
102 | /// runtime calls. This allows it to be faster. |
103 | /// |
104 | inline ARCInstKind GetBasicARCInstKind(const Value *V) { |
105 | if (const CallInst *CI = dyn_cast<CallInst>(Val: V)) { |
106 | if (const Function *F = CI->getCalledFunction()) |
107 | return GetFunctionClass(F); |
108 | // Otherwise, be conservative. |
109 | return ARCInstKind::CallOrUser; |
110 | } |
111 | |
112 | // Otherwise, be conservative. |
113 | return isa<InvokeInst>(Val: V) ? ARCInstKind::CallOrUser : ARCInstKind::User; |
114 | } |
115 | |
116 | /// Map V to its ARCInstKind equivalence class. |
117 | ARCInstKind GetARCInstKind(const Value *V); |
118 | |
119 | /// Returns false if conservatively we can prove that any instruction mapped to |
120 | /// this kind can not decrement ref counts. Returns true otherwise. |
121 | bool CanDecrementRefCount(ARCInstKind Kind); |
122 | |
123 | } // end namespace objcarc |
124 | } // end namespace llvm |
125 | |
126 | #endif |
127 | |