xref: /llvm-project/clang/lib/CIR/CodeGen/CIRGenModule.cpp (revision 8e329593313bb792592529ee825a52683108df99)
1 //===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===//
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 #include "CIRGenModule.h"
14 
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/DeclBase.h"
17 #include "clang/AST/GlobalDecl.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/CIR/Dialect/IR/CIRDialect.h"
20 
21 #include "mlir/IR/BuiltinOps.h"
22 #include "mlir/IR/Location.h"
23 #include "mlir/IR/MLIRContext.h"
24 
25 using namespace clang;
26 using namespace clang::CIRGen;
27 
28 CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
29                            clang::ASTContext &astContext,
30                            const clang::CodeGenOptions &cgo,
31                            DiagnosticsEngine &diags)
32     : builder(mlirContext, *this), astContext(astContext),
33       langOpts(astContext.getLangOpts()),
34       theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))},
35       diags(diags), target(astContext.getTargetInfo()), genTypes(*this) {
36 
37   // Initialize cached types
38   VoidTy = cir::VoidType::get(&getMLIRContext());
39   SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true);
40   SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true);
41   SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true);
42   SInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true);
43   SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
44   UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
45   UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
46   UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
47   UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
48   UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false);
49   FP16Ty = cir::FP16Type::get(&getMLIRContext());
50   BFloat16Ty = cir::BF16Type::get(&getMLIRContext());
51   FloatTy = cir::SingleType::get(&getMLIRContext());
52   DoubleTy = cir::DoubleType::get(&getMLIRContext());
53   FP80Ty = cir::FP80Type::get(&getMLIRContext());
54   FP128Ty = cir::FP128Type::get(&getMLIRContext());
55 }
56 
57 mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
58   assert(cLoc.isValid() && "expected valid source location");
59   const SourceManager &sm = astContext.getSourceManager();
60   PresumedLoc pLoc = sm.getPresumedLoc(cLoc);
61   StringRef filename = pLoc.getFilename();
62   return mlir::FileLineColLoc::get(builder.getStringAttr(filename),
63                                    pLoc.getLine(), pLoc.getColumn());
64 }
65 
66 mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
67   assert(cRange.isValid() && "expected a valid source range");
68   mlir::Location begin = getLoc(cRange.getBegin());
69   mlir::Location end = getLoc(cRange.getEnd());
70   mlir::Attribute metadata;
71   return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext());
72 }
73 
74 void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
75   const auto *global = cast<ValueDecl>(gd.getDecl());
76 
77   if (const auto *fd = dyn_cast<FunctionDecl>(global)) {
78     // Update deferred annotations with the latest declaration if the function
79     // was already used or defined.
80     if (fd->hasAttr<AnnotateAttr>())
81       errorNYI(fd->getSourceRange(), "deferredAnnotations");
82     if (!fd->doesThisDeclarationHaveABody()) {
83       if (!fd->doesDeclarationForceExternallyVisibleDefinition())
84         return;
85 
86       errorNYI(fd->getSourceRange(),
87                "function declaration that forces code gen");
88       return;
89     }
90   } else {
91     assert(cast<VarDecl>(global)->isFileVarDecl() &&
92            "Cannot emit local var decl as global");
93   }
94 
95   // TODO(CIR): Defer emitting some global definitions until later
96   emitGlobalDefinition(gd);
97 }
98 
99 void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
100                                                 mlir::Operation *op) {
101   auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
102   if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) {
103     auto funcOp = builder.create<cir::FuncOp>(
104         getLoc(funcDecl->getSourceRange()), identifier->getName());
105     theModule.push_back(funcOp);
106   } else {
107     errorNYI(funcDecl->getSourceRange().getBegin(),
108              "function definition with a non-identifier for a name");
109   }
110 }
111 
112 void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
113                                            bool isTentative) {
114   mlir::Type type = getTypes().convertType(vd->getType());
115   if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
116     auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
117                                                identifier->getName(), type);
118     // TODO(CIR): This code for processing initial values is a placeholder
119     // until class ConstantEmitter is upstreamed and the code for processing
120     // constant expressions is filled out.  Only the most basic handling of
121     // certain constant expressions is implemented for now.
122     const VarDecl *initDecl;
123     const Expr *initExpr = vd->getAnyInitializer(initDecl);
124     if (initExpr) {
125       mlir::Attribute initializer;
126       if (APValue *value = initDecl->evaluateValue()) {
127         switch (value->getKind()) {
128         case APValue::Int: {
129           initializer = builder.getAttr<cir::IntAttr>(type, value->getInt());
130           break;
131         }
132         case APValue::Float: {
133           initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat());
134           break;
135         }
136         case APValue::LValue: {
137           if (value->getLValueBase()) {
138             errorNYI(initExpr->getSourceRange(),
139                      "non-null pointer initialization");
140           } else {
141             if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) {
142               initializer = builder.getConstPtrAttr(
143                   ptrType, value->getLValueOffset().getQuantity());
144             } else {
145               llvm_unreachable(
146                   "non-pointer variable initialized with a pointer");
147             }
148           }
149           break;
150         }
151         default:
152           errorNYI(initExpr->getSourceRange(), "unsupported initializer kind");
153           break;
154         }
155       } else {
156         errorNYI(initExpr->getSourceRange(), "non-constant initializer");
157       }
158       varOp.setInitialValueAttr(initializer);
159     }
160     theModule.push_back(varOp);
161   } else {
162     errorNYI(vd->getSourceRange().getBegin(),
163              "variable definition with a non-identifier for a name");
164   }
165 }
166 
167 void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
168                                         mlir::Operation *op) {
169   const auto *decl = cast<ValueDecl>(gd.getDecl());
170   if (const auto *fd = dyn_cast<FunctionDecl>(decl)) {
171     // TODO(CIR): Skip generation of CIR for functions with available_externally
172     // linkage at -O0.
173 
174     if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) {
175       // Make sure to emit the definition(s) before we emit the thunks. This is
176       // necessary for the generation of certain thunks.
177       (void)method;
178       errorNYI(method->getSourceRange(), "member function");
179       return;
180     }
181 
182     if (fd->isMultiVersion())
183       errorNYI(fd->getSourceRange(), "multiversion functions");
184     emitGlobalFunctionDefinition(gd, op);
185     return;
186   }
187 
188   if (const auto *vd = dyn_cast<VarDecl>(decl))
189     return emitGlobalVarDefinition(vd, !vd->hasDefinition());
190 
191   llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
192 }
193 
194 // Emit code for a single top level declaration.
195 void CIRGenModule::emitTopLevelDecl(Decl *decl) {
196 
197   // Ignore dependent declarations.
198   if (decl->isTemplated())
199     return;
200 
201   switch (decl->getKind()) {
202   default:
203     errorNYI(decl->getBeginLoc(), "declaration of kind",
204              decl->getDeclKindName());
205     break;
206 
207   case Decl::Function: {
208     auto *fd = cast<FunctionDecl>(decl);
209     // Consteval functions shouldn't be emitted.
210     if (!fd->isConsteval())
211       emitGlobal(fd);
212     break;
213   }
214 
215   case Decl::Var: {
216     auto *vd = cast<VarDecl>(decl);
217     emitGlobal(vd);
218     break;
219   }
220   }
221 }
222 
223 DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
224                                          llvm::StringRef feature) {
225   unsigned diagID = diags.getCustomDiagID(
226       DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
227   return diags.Report(loc, diagID) << feature;
228 }
229 
230 DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
231                                          llvm::StringRef feature) {
232   return errorNYI(loc.getBegin(), feature) << loc;
233 }
234