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
29namespace clang {
30
31enum class DynamicInitKind : unsigned {
32 NoStub = 0,
33 Initializer,
34 AtExit,
35 GlobalArrayDestructor
36};
37
38enum 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///
55class 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
67public:
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
201namespace 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