1 //===- GlobalDecl.h - Global declaration holder -----------------*- 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 // A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor
10 // together with its type.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_AST_GLOBALDECL_H
15 #define LLVM_CLANG_AST_GLOBALDECL_H
16 
17 #include "clang/AST/Attr.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/DeclOpenMP.h"
21 #include "clang/Basic/ABI.h"
22 #include "clang/Basic/LLVM.h"
23 #include "llvm/ADT/DenseMapInfo.h"
24 #include "llvm/ADT/PointerIntPair.h"
25 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/type_traits.h"
27 #include <cassert>
28 
29 namespace clang {
30 
31 enum class DynamicInitKind : unsigned {
32   NoStub = 0,
33   Initializer,
34   AtExit,
35   GlobalArrayDestructor
36 };
37 
38 enum class KernelReferenceKind : unsigned {
39   Kernel = 0,
40   Stub = 1,
41 };
42 
43 /// GlobalDecl - represents a global declaration. This can either be a
44 /// CXXConstructorDecl and the constructor type (Base, Complete).
45 /// a CXXDestructorDecl and the destructor type (Base, Complete),
46 /// a FunctionDecl and the kernel reference type (Kernel, Stub), or
47 /// a VarDecl, a FunctionDecl or a BlockDecl.
48 ///
49 /// When a new type of GlobalDecl is added, the following places should
50 /// be updated to convert a Decl* to a GlobalDecl:
51 /// PredefinedExpr::ComputeName() in lib/AST/Expr.cpp.
52 /// getParentOfLocalEntity() in lib/AST/ItaniumMangle.cpp
53 /// ASTNameGenerator::Implementation::writeFuncOrVarName in lib/AST/Mangle.cpp
54 ///
55 class GlobalDecl {
56   llvm::PointerIntPair<const Decl *, 3> Value;
57   unsigned MultiVersionIndex = 0;
58 
59   void Init(const Decl *D) {
60     assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
61     assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
62     assert(!D->hasAttr<CUDAGlobalAttr>() && "Use other ctor with GPU kernels!");
63 
64     Value.setPointer(D);
65   }
66 
67 public:
68   GlobalDecl() = default;
69   GlobalDecl(const VarDecl *D) { Init(D);}
70   GlobalDecl(const FunctionDecl *D, unsigned MVIndex = 0)
71       : MultiVersionIndex(MVIndex) {
72     if (!D->hasAttr<CUDAGlobalAttr>()) {
73       Init(D);
74       return;
75     }
76     Value.setPointerAndInt(D, unsigned(getDefaultKernelReference(D)));
77   }
78   GlobalDecl(const FunctionDecl *D, KernelReferenceKind Kind)
79       : Value(D, unsigned(Kind)) {
80     assert(D->hasAttr<CUDAGlobalAttr>() && "Decl is not a GPU kernel!");
81   }
82   GlobalDecl(const NamedDecl *D) { Init(D); }
83   GlobalDecl(const BlockDecl *D) { Init(D); }
84   GlobalDecl(const CapturedDecl *D) { Init(D); }
85   GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
86   GlobalDecl(const OMPDeclareReductionDecl *D) { Init(D); }
87   GlobalDecl(const OMPDeclareMapperDecl *D) { Init(D); }
88   GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {}
89   GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {}
90   GlobalDecl(const VarDecl *D, DynamicInitKind StubKind)
91       : Value(D, unsigned(StubKind)) {}
92 
93   GlobalDecl getCanonicalDecl() const {
94     GlobalDecl CanonGD;
95     CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl());
96     CanonGD.Value.setInt(Value.getInt());
97     CanonGD.MultiVersionIndex = MultiVersionIndex;
98 
99     return CanonGD;
100   }
101 
102   const Decl *getDecl() const { return Value.getPointer(); }
103 
104   CXXCtorType getCtorType() const {
105     assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
106     return static_cast<CXXCtorType>(Value.getInt());
107   }
108 
109   CXXDtorType getDtorType() const {
110     assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
111     return static_cast<CXXDtorType>(Value.getInt());
112   }
113 
114   DynamicInitKind getDynamicInitKind() const {
115     assert(isa<VarDecl>(getDecl()) &&
116            cast<VarDecl>(getDecl())->hasGlobalStorage() &&
117            "Decl is not a global variable!");
118     return static_cast<DynamicInitKind>(Value.getInt());
119   }
120 
121   unsigned getMultiVersionIndex() const {
122     assert(isa<FunctionDecl>(
123                getDecl()) &&
124                !cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>() &&
125            !isa<CXXConstructorDecl>(getDecl()) &&
126            !isa<CXXDestructorDecl>(getDecl()) &&
127            "Decl is not a plain FunctionDecl!");
128     return MultiVersionIndex;
129   }
130 
131   KernelReferenceKind getKernelReferenceKind() const {
132     assert(isa<FunctionDecl>(getDecl()) &&
133            cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>() &&
134            "Decl is not a GPU kernel!");
135     return static_cast<KernelReferenceKind>(Value.getInt());
136   }
137 
138   friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) {
139     return LHS.Value == RHS.Value &&
140            LHS.MultiVersionIndex == RHS.MultiVersionIndex;
141   }
142 
143   void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
144 
145   explicit operator bool() const { return getAsOpaquePtr(); }
146 
147   static GlobalDecl getFromOpaquePtr(void *P) {
148     GlobalDecl GD;
149     GD.Value.setFromOpaqueValue(P);
150     return GD;
151   }
152 
153   static KernelReferenceKind getDefaultKernelReference(const FunctionDecl *D) {
154     return D->getLangOpts().CUDAIsDevice ? KernelReferenceKind::Kernel
155                                          : KernelReferenceKind::Stub;
156   }
157 
158   GlobalDecl getWithDecl(const Decl *D) {
159     GlobalDecl Result(*this);
160     Result.Value.setPointer(D);
161     return Result;
162   }
163 
164   GlobalDecl getWithCtorType(CXXCtorType Type) {
165     assert(isa<CXXConstructorDecl>(getDecl()));
166     GlobalDecl Result(*this);
167     Result.Value.setInt(Type);
168     return Result;
169   }
170 
171   GlobalDecl getWithDtorType(CXXDtorType Type) {
172     assert(isa<CXXDestructorDecl>(getDecl()));
173     GlobalDecl Result(*this);
174     Result.Value.setInt(Type);
175     return Result;
176   }
177 
178   GlobalDecl getWithMultiVersionIndex(unsigned Index) {
179     assert(isa<FunctionDecl>(getDecl()) &&
180            !cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>() &&
181            !isa<CXXConstructorDecl>(getDecl()) &&
182            !isa<CXXDestructorDecl>(getDecl()) &&
183            "Decl is not a plain FunctionDecl!");
184     GlobalDecl Result(*this);
185     Result.MultiVersionIndex = Index;
186     return Result;
187   }
188 
189   GlobalDecl getWithKernelReferenceKind(KernelReferenceKind Kind) {
190     assert(isa<FunctionDecl>(getDecl()) &&
191            cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>() &&
192            "Decl is not a GPU kernel!");
193     GlobalDecl Result(*this);
194     Result.Value.setInt(unsigned(Kind));
195     return Result;
196   }
197 };
198 
199 } // namespace clang
200 
201 namespace llvm {
202 
203   template<> struct DenseMapInfo<clang::GlobalDecl> {
204     static inline clang::GlobalDecl getEmptyKey() {
205       return clang::GlobalDecl();
206     }
207 
208     static inline clang::GlobalDecl getTombstoneKey() {
209       return clang::GlobalDecl::
210         getFromOpaquePtr(reinterpret_cast<void*>(-1));
211     }
212 
213     static unsigned getHashValue(clang::GlobalDecl GD) {
214       return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr());
215     }
216 
217     static bool isEqual(clang::GlobalDecl LHS,
218                         clang::GlobalDecl RHS) {
219       return LHS == RHS;
220     }
221   };
222 
223 } // namespace llvm
224 
225 #endif // LLVM_CLANG_AST_GLOBALDECL_H
226