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