1 | //===--- CIRGenModule.h - Per-Module state for CIR gen ----------*- 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 | // This is the internal per-translation-unit state used for CIR translation. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H |
14 | #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H |
15 | |
16 | #include "CIRGenBuilder.h" |
17 | #include "CIRGenTypeCache.h" |
18 | #include "CIRGenTypes.h" |
19 | #include "CIRGenValue.h" |
20 | |
21 | #include "clang/AST/CharUnits.h" |
22 | #include "clang/CIR/Dialect/IR/CIRDataLayout.h" |
23 | #include "clang/CIR/Dialect/IR/CIRDialect.h" |
24 | |
25 | #include "TargetInfo.h" |
26 | #include "mlir/IR/Builders.h" |
27 | #include "mlir/IR/BuiltinOps.h" |
28 | #include "mlir/IR/MLIRContext.h" |
29 | #include "clang/AST/Decl.h" |
30 | #include "clang/Basic/SourceManager.h" |
31 | #include "clang/Basic/TargetInfo.h" |
32 | #include "clang/CIR/Dialect/IR/CIROpsEnums.h" |
33 | #include "llvm/ADT/StringRef.h" |
34 | #include "llvm/TargetParser/Triple.h" |
35 | |
36 | namespace clang { |
37 | class ASTContext; |
38 | class CodeGenOptions; |
39 | class Decl; |
40 | class GlobalDecl; |
41 | class LangOptions; |
42 | class TargetInfo; |
43 | class VarDecl; |
44 | |
45 | namespace CIRGen { |
46 | |
47 | class CIRGenFunction; |
48 | class CIRGenCXXABI; |
49 | |
50 | enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true }; |
51 | |
52 | /// This class organizes the cross-function state that is used while generating |
53 | /// CIR code. |
54 | class CIRGenModule : public CIRGenTypeCache { |
55 | CIRGenModule(CIRGenModule &) = delete; |
56 | CIRGenModule &operator=(CIRGenModule &) = delete; |
57 | |
58 | public: |
59 | CIRGenModule(mlir::MLIRContext &mlirContext, clang::ASTContext &astContext, |
60 | const clang::CodeGenOptions &cgo, |
61 | clang::DiagnosticsEngine &diags); |
62 | |
63 | ~CIRGenModule(); |
64 | |
65 | private: |
66 | mutable std::unique_ptr<TargetCIRGenInfo> theTargetCIRGenInfo; |
67 | |
68 | CIRGenBuilderTy builder; |
69 | |
70 | /// Hold Clang AST information. |
71 | clang::ASTContext &astContext; |
72 | |
73 | const clang::LangOptions &langOpts; |
74 | |
75 | const clang::CodeGenOptions &codeGenOpts; |
76 | |
77 | /// A "module" matches a c/cpp source file: containing a list of functions. |
78 | mlir::ModuleOp theModule; |
79 | |
80 | clang::DiagnosticsEngine &diags; |
81 | |
82 | const clang::TargetInfo ⌖ |
83 | |
84 | std::unique_ptr<CIRGenCXXABI> abi; |
85 | |
86 | CIRGenTypes genTypes; |
87 | |
88 | /// Per-function codegen information. Updated everytime emitCIR is called |
89 | /// for FunctionDecls's. |
90 | CIRGenFunction *curCGF = nullptr; |
91 | |
92 | public: |
93 | mlir::ModuleOp getModule() const { return theModule; } |
94 | CIRGenBuilderTy &getBuilder() { return builder; } |
95 | clang::ASTContext &getASTContext() const { return astContext; } |
96 | const clang::TargetInfo &getTarget() const { return target; } |
97 | const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; } |
98 | CIRGenTypes &getTypes() { return genTypes; } |
99 | const clang::LangOptions &getLangOpts() const { return langOpts; } |
100 | |
101 | CIRGenCXXABI &getCXXABI() const { return *abi; } |
102 | mlir::MLIRContext &getMLIRContext() { return *builder.getContext(); } |
103 | |
104 | const cir::CIRDataLayout getDataLayout() const { |
105 | // FIXME(cir): instead of creating a CIRDataLayout every time, set it as an |
106 | // attribute for the CIRModule class. |
107 | return cir::CIRDataLayout(theModule); |
108 | } |
109 | |
110 | /// ------- |
111 | /// Handling globals |
112 | /// ------- |
113 | |
114 | mlir::Operation *lastGlobalOp = nullptr; |
115 | |
116 | mlir::Operation *getGlobalValue(llvm::StringRef ref); |
117 | |
118 | /// If the specified mangled name is not in the module, create and return an |
119 | /// mlir::GlobalOp value |
120 | cir::GlobalOp getOrCreateCIRGlobal(llvm::StringRef mangledName, mlir::Type ty, |
121 | LangAS langAS, const VarDecl *d, |
122 | ForDefinition_t isForDefinition); |
123 | |
124 | cir::GlobalOp getOrCreateCIRGlobal(const VarDecl *d, mlir::Type ty, |
125 | ForDefinition_t isForDefinition); |
126 | |
127 | static cir::GlobalOp createGlobalOp(CIRGenModule &cgm, mlir::Location loc, |
128 | llvm::StringRef name, mlir::Type t, |
129 | mlir::Operation *insertPoint = nullptr); |
130 | |
131 | llvm::StringMap<unsigned> cgGlobalNames; |
132 | std::string getUniqueGlobalName(const std::string &baseName); |
133 | |
134 | /// Return the mlir::Value for the address of the given global variable. |
135 | /// If Ty is non-null and if the global doesn't exist, then it will be created |
136 | /// with the specified type instead of whatever the normal requested type |
137 | /// would be. If IsForDefinition is true, it is guaranteed that an actual |
138 | /// global with type Ty will be returned, not conversion of a variable with |
139 | /// the same mangled name but some other type. |
140 | mlir::Value |
141 | getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty = {}, |
142 | ForDefinition_t isForDefinition = NotForDefinition); |
143 | |
144 | CharUnits computeNonVirtualBaseClassOffset( |
145 | const CXXRecordDecl *derivedClass, |
146 | llvm::iterator_range<CastExpr::path_const_iterator> path); |
147 | |
148 | /// Return a constant array for the given string. |
149 | mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e); |
150 | |
151 | /// Return a global symbol reference to a constant array for the given string |
152 | /// literal. |
153 | cir::GlobalOp getGlobalForStringLiteral(const StringLiteral *s, |
154 | llvm::StringRef name = ".str" ); |
155 | |
156 | /// Set attributes which are common to any form of a global definition (alias, |
157 | /// Objective-C method, function, global variable). |
158 | /// |
159 | /// NOTE: This should only be called for definitions. |
160 | void setCommonAttributes(GlobalDecl gd, mlir::Operation *op); |
161 | |
162 | const TargetCIRGenInfo &getTargetCIRGenInfo(); |
163 | |
164 | /// Helpers to convert the presumed location of Clang's SourceLocation to an |
165 | /// MLIR Location. |
166 | mlir::Location getLoc(clang::SourceLocation cLoc); |
167 | mlir::Location getLoc(clang::SourceRange cRange); |
168 | |
169 | /// Return the best known alignment for an unknown pointer to a |
170 | /// particular class. |
171 | clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *rd); |
172 | |
173 | /// FIXME: this could likely be a common helper and not necessarily related |
174 | /// with codegen. |
175 | clang::CharUnits getNaturalTypeAlignment(clang::QualType t, |
176 | LValueBaseInfo *baseInfo); |
177 | |
178 | cir::FuncOp |
179 | getAddrOfCXXStructor(clang::GlobalDecl gd, |
180 | const CIRGenFunctionInfo *fnInfo = nullptr, |
181 | cir::FuncType fnType = nullptr, bool dontDefer = false, |
182 | ForDefinition_t isForDefinition = NotForDefinition) { |
183 | return getAddrAndTypeOfCXXStructor(gd, fnInfo, fnType, dontDefer, |
184 | isForDefinition) |
185 | .second; |
186 | } |
187 | |
188 | std::pair<cir::FuncType, cir::FuncOp> getAddrAndTypeOfCXXStructor( |
189 | clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo = nullptr, |
190 | cir::FuncType fnType = nullptr, bool dontDefer = false, |
191 | ForDefinition_t isForDefinition = NotForDefinition); |
192 | |
193 | /// This contains all the decls which have definitions but which are deferred |
194 | /// for emission and therefore should only be output if they are actually |
195 | /// used. If a decl is in this, then it is known to have not been referenced |
196 | /// yet. |
197 | std::map<llvm::StringRef, clang::GlobalDecl> deferredDecls; |
198 | |
199 | // This is a list of deferred decls which we have seen that *are* actually |
200 | // referenced. These get code generated when the module is done. |
201 | std::vector<clang::GlobalDecl> deferredDeclsToEmit; |
202 | void addDeferredDeclToEmit(clang::GlobalDecl GD) { |
203 | deferredDeclsToEmit.emplace_back(args&: GD); |
204 | } |
205 | |
206 | void emitTopLevelDecl(clang::Decl *decl); |
207 | |
208 | /// Determine whether the definition must be emitted; if this returns \c |
209 | /// false, the definition can be emitted lazily if it's used. |
210 | bool mustBeEmitted(const clang::ValueDecl *d); |
211 | |
212 | /// Determine whether the definition can be emitted eagerly, or should be |
213 | /// delayed until the end of the translation unit. This is relevant for |
214 | /// definitions whose linkage can change, e.g. implicit function |
215 | /// instantiations which may later be explicitly instantiated. |
216 | bool mayBeEmittedEagerly(const clang::ValueDecl *d); |
217 | |
218 | bool verifyModule() const; |
219 | |
220 | /// Return the address of the given function. If funcType is non-null, then |
221 | /// this function will use the specified type if it has to create it. |
222 | // TODO: this is a bit weird as `GetAddr` given we give back a FuncOp? |
223 | cir::FuncOp |
224 | getAddrOfFunction(clang::GlobalDecl gd, mlir::Type funcType = nullptr, |
225 | bool forVTable = false, bool dontDefer = false, |
226 | ForDefinition_t isForDefinition = NotForDefinition); |
227 | |
228 | mlir::Operation * |
229 | getAddrOfGlobal(clang::GlobalDecl gd, |
230 | ForDefinition_t isForDefinition = NotForDefinition); |
231 | |
232 | /// Emit code for a single global function or variable declaration. Forward |
233 | /// declarations are emitted lazily. |
234 | void emitGlobal(clang::GlobalDecl gd); |
235 | |
236 | mlir::Type convertType(clang::QualType type); |
237 | |
238 | /// Set the visibility for the given global. |
239 | void setGlobalVisibility(mlir::Operation *op, const NamedDecl *d) const; |
240 | void setDSOLocal(mlir::Operation *op) const; |
241 | void setDSOLocal(cir::CIRGlobalValueInterface gv) const; |
242 | |
243 | /// Set visibility, dllimport/dllexport and dso_local. |
244 | /// This must be called after dllimport/dllexport is set. |
245 | void setGVProperties(mlir::Operation *op, const NamedDecl *d) const; |
246 | void setGVPropertiesAux(mlir::Operation *op, const NamedDecl *d) const; |
247 | |
248 | void emitGlobalDefinition(clang::GlobalDecl gd, |
249 | mlir::Operation *op = nullptr); |
250 | void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op); |
251 | void emitGlobalVarDefinition(const clang::VarDecl *vd, |
252 | bool isTentative = false); |
253 | |
254 | void emitGlobalOpenACCDecl(const clang::OpenACCConstructDecl *cd); |
255 | |
256 | // C++ related functions. |
257 | void emitDeclContext(const DeclContext *dc); |
258 | |
259 | /// Return the result of value-initializing the given type, i.e. a null |
260 | /// expression of the given type. |
261 | mlir::Value emitNullConstant(QualType t, mlir::Location loc); |
262 | |
263 | llvm::StringRef getMangledName(clang::GlobalDecl gd); |
264 | |
265 | void emitTentativeDefinition(const VarDecl *d); |
266 | |
267 | // Make sure that this type is translated. |
268 | void updateCompletedType(const clang::TagDecl *td); |
269 | |
270 | bool supportsCOMDAT() const; |
271 | void maybeSetTrivialComdat(const clang::Decl &d, mlir::Operation *op); |
272 | |
273 | static void setInitializer(cir::GlobalOp &op, mlir::Attribute value); |
274 | |
275 | cir::FuncOp |
276 | getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType, |
277 | clang::GlobalDecl gd, bool forVTable, |
278 | bool dontDefer = false, bool isThunk = false, |
279 | ForDefinition_t isForDefinition = NotForDefinition, |
280 | mlir::ArrayAttr = {}); |
281 | |
282 | cir::FuncOp createCIRFunction(mlir::Location loc, llvm::StringRef name, |
283 | cir::FuncType funcType, |
284 | const clang::FunctionDecl *funcDecl); |
285 | |
286 | mlir::IntegerAttr getSize(CharUnits size) { |
287 | return builder.getSizeFromCharUnits(size); |
288 | } |
289 | |
290 | /// Emit any needed decls for which code generation was deferred. |
291 | void emitDeferred(); |
292 | |
293 | /// Helper for `emitDeferred` to apply actual codegen. |
294 | void emitGlobalDecl(const clang::GlobalDecl &d); |
295 | |
296 | const llvm::Triple &getTriple() const { return target.getTriple(); } |
297 | |
298 | // Finalize CIR code generation. |
299 | void release(); |
300 | |
301 | /// ------- |
302 | /// Visibility and Linkage |
303 | /// ------- |
304 | |
305 | static mlir::SymbolTable::Visibility |
306 | getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind GLK); |
307 | static cir::VisibilityKind getGlobalVisibilityKindFromClangVisibility( |
308 | clang::VisibilityAttr::VisibilityType visibility); |
309 | cir::VisibilityAttr getGlobalVisibilityAttrFromDecl(const Decl *decl); |
310 | static mlir::SymbolTable::Visibility getMLIRVisibility(cir::GlobalOp op); |
311 | |
312 | cir::GlobalLinkageKind getCIRLinkageForDeclarator(const DeclaratorDecl *dd, |
313 | GVALinkage linkage, |
314 | bool isConstantVariable); |
315 | |
316 | cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *vd, |
317 | bool isConstant); |
318 | |
319 | /// Helpers to emit "not yet implemented" error diagnostics |
320 | DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef); |
321 | |
322 | template <typename T> |
323 | DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature, |
324 | const T &name) { |
325 | unsigned diagID = |
326 | diags.getCustomDiagID(L: DiagnosticsEngine::Error, |
327 | FormatString: "ClangIR code gen Not Yet Implemented: %0: %1" ); |
328 | return diags.Report(Loc: loc, DiagID: diagID) << feature << name; |
329 | } |
330 | |
331 | DiagnosticBuilder errorNYI(mlir::Location loc, llvm::StringRef feature) { |
332 | // TODO: Convert the location to a SourceLocation |
333 | unsigned diagID = diags.getCustomDiagID( |
334 | L: DiagnosticsEngine::Error, FormatString: "ClangIR code gen Not Yet Implemented: %0" ); |
335 | return diags.Report(DiagID: diagID) << feature; |
336 | } |
337 | |
338 | DiagnosticBuilder errorNYI(llvm::StringRef feature) const { |
339 | // TODO: Make a default location? currSrcLoc? |
340 | unsigned diagID = diags.getCustomDiagID( |
341 | L: DiagnosticsEngine::Error, FormatString: "ClangIR code gen Not Yet Implemented: %0" ); |
342 | return diags.Report(DiagID: diagID) << feature; |
343 | } |
344 | |
345 | DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef); |
346 | |
347 | template <typename T> |
348 | DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature, |
349 | const T &name) { |
350 | return errorNYI(loc.getBegin(), feature, name) << loc; |
351 | } |
352 | |
353 | private: |
354 | // An ordered map of canonical GlobalDecls to their mangled names. |
355 | llvm::MapVector<clang::GlobalDecl, llvm::StringRef> mangledDeclNames; |
356 | llvm::StringMap<clang::GlobalDecl, llvm::BumpPtrAllocator> manglings; |
357 | |
358 | void setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op); |
359 | }; |
360 | } // namespace CIRGen |
361 | |
362 | } // namespace clang |
363 | |
364 | #endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H |
365 | |