1 //===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This is the internal per-translation-unit state used for CIR translation.
11 //===----------------------------------------------------------------------===//
13 #include "CIRGenModule.h"
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"
21 #include "mlir/IR/BuiltinOps.h"
22 #include "mlir/IR/Location.h"
23 #include "mlir/IR/MLIRContext.h"
25 using namespace clang
;
26 using namespace clang::CIRGen
;
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) {
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());
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());
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());
74 void CIRGenModule::emitGlobal(clang::GlobalDecl gd
) {
75 const auto *global
= cast
<ValueDecl
>(gd
.getDecl());
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())
86 errorNYI(fd
->getSourceRange(),
87 "function declaration that forces code gen");
91 assert(cast
<VarDecl
>(global
)->isFileVarDecl() &&
92 "Cannot emit local var decl as global");
95 // TODO(CIR): Defer emitting some global definitions until later
96 emitGlobalDefinition(gd
);
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
);
107 errorNYI(funcDecl
->getSourceRange().getBegin(),
108 "function definition with a non-identifier for a name");
112 void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl
*vd
,
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
);
125 mlir::Attribute initializer
;
126 if (APValue
*value
= initDecl
->evaluateValue()) {
127 switch (value
->getKind()) {
129 initializer
= builder
.getAttr
<cir::IntAttr
>(type
, value
->getInt());
132 case APValue::Float
: {
133 initializer
= builder
.getAttr
<cir::FPAttr
>(type
, value
->getFloat());
136 case APValue::LValue
: {
137 if (value
->getLValueBase()) {
138 errorNYI(initExpr
->getSourceRange(),
139 "non-null pointer initialization");
141 if (auto ptrType
= mlir::dyn_cast
<cir::PointerType
>(type
)) {
142 initializer
= builder
.getConstPtrAttr(
143 ptrType
, value
->getLValueOffset().getQuantity());
146 "non-pointer variable initialized with a pointer");
152 errorNYI(initExpr
->getSourceRange(), "unsupported initializer kind");
156 errorNYI(initExpr
->getSourceRange(), "non-constant initializer");
158 varOp
.setInitialValueAttr(initializer
);
160 theModule
.push_back(varOp
);
162 errorNYI(vd
->getSourceRange().getBegin(),
163 "variable definition with a non-identifier for a name");
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
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.
178 errorNYI(method
->getSourceRange(), "member function");
182 if (fd
->isMultiVersion())
183 errorNYI(fd
->getSourceRange(), "multiversion functions");
184 emitGlobalFunctionDefinition(gd
, op
);
188 if (const auto *vd
= dyn_cast
<VarDecl
>(decl
))
189 return emitGlobalVarDefinition(vd
, !vd
->hasDefinition());
191 llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
194 // Emit code for a single top level declaration.
195 void CIRGenModule::emitTopLevelDecl(Decl
*decl
) {
197 // Ignore dependent declarations.
198 if (decl
->isTemplated())
201 switch (decl
->getKind()) {
203 errorNYI(decl
->getBeginLoc(), "declaration of kind",
204 decl
->getDeclKindName());
207 case Decl::Function
: {
208 auto *fd
= cast
<FunctionDecl
>(decl
);
209 // Consteval functions shouldn't be emitted.
210 if (!fd
->isConsteval())
216 auto *vd
= cast
<VarDecl
>(decl
);
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
;
230 DiagnosticBuilder
CIRGenModule::errorNYI(SourceRange loc
,
231 llvm::StringRef feature
) {
232 return errorNYI(loc
.getBegin(), feature
) << loc
;