Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 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" |
Amr Hesham | 6aeae62 | 2025-03-19 21:29:37 +0100 | [diff] [blame] | 14 | #include "CIRGenConstantEmitter.h" |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 15 | #include "CIRGenFunction.h" |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 16 | |
| 17 | #include "clang/AST/ASTContext.h" |
| 18 | #include "clang/AST/DeclBase.h" |
Erich Keane | 231aa30 | 2025-04-08 10:06:28 -0700 | [diff] [blame] | 19 | #include "clang/AST/DeclOpenACC.h" |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 20 | #include "clang/AST/GlobalDecl.h" |
| 21 | #include "clang/Basic/SourceManager.h" |
| 22 | #include "clang/CIR/Dialect/IR/CIRDialect.h" |
Morris Hafner | 710de09 | 2025-03-06 19:17:58 +0100 | [diff] [blame] | 23 | #include "clang/CIR/MissingFeatures.h" |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 24 | |
| 25 | #include "mlir/IR/BuiltinOps.h" |
| 26 | #include "mlir/IR/Location.h" |
| 27 | #include "mlir/IR/MLIRContext.h" |
Andy Kaylor | 39ce995 | 2025-03-19 09:42:03 -0700 | [diff] [blame] | 28 | #include "mlir/IR/Verifier.h" |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 29 | |
Shoaib Meenai | 40e5450 | 2024-11-08 10:41:39 -0800 | [diff] [blame] | 30 | using namespace clang; |
| 31 | using namespace clang::CIRGen; |
| 32 | |
David Olsen | 7eb73b9 | 2024-12-10 13:46:07 -0800 | [diff] [blame] | 33 | CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, |
| 34 | clang::ASTContext &astContext, |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 35 | const clang::CodeGenOptions &cgo, |
| 36 | DiagnosticsEngine &diags) |
David Olsen | 7eb73b9 | 2024-12-10 13:46:07 -0800 | [diff] [blame] | 37 | : builder(mlirContext, *this), astContext(astContext), |
Morris Hafner | 710de09 | 2025-03-06 19:17:58 +0100 | [diff] [blame] | 38 | langOpts(astContext.getLangOpts()), codeGenOpts(cgo), |
David Olsen | 7eb73b9 | 2024-12-10 13:46:07 -0800 | [diff] [blame] | 39 | theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))}, |
| 40 | diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { |
David Olsen | ffb19f4 | 2024-12-10 11:29:48 -0800 | [diff] [blame] | 41 | |
| 42 | // Initialize cached types |
David Olsen | 8ae8a90 | 2024-12-20 12:22:25 -0800 | [diff] [blame] | 43 | VoidTy = cir::VoidType::get(&getMLIRContext()); |
David Olsen | ffb19f4 | 2024-12-10 11:29:48 -0800 | [diff] [blame] | 44 | SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); |
| 45 | SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); |
| 46 | SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); |
| 47 | SInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true); |
| 48 | SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true); |
| 49 | UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false); |
| 50 | UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false); |
| 51 | UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); |
| 52 | UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); |
| 53 | UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); |
David Olsen | 8ae8a90 | 2024-12-20 12:22:25 -0800 | [diff] [blame] | 54 | FP16Ty = cir::FP16Type::get(&getMLIRContext()); |
| 55 | BFloat16Ty = cir::BF16Type::get(&getMLIRContext()); |
| 56 | FloatTy = cir::SingleType::get(&getMLIRContext()); |
| 57 | DoubleTy = cir::DoubleType::get(&getMLIRContext()); |
| 58 | FP80Ty = cir::FP80Type::get(&getMLIRContext()); |
| 59 | FP128Ty = cir::FP128Type::get(&getMLIRContext()); |
Andy Kaylor | 75ea7ae | 2025-02-19 09:08:37 -0800 | [diff] [blame] | 60 | |
Amr Hesham | 262b9b5 | 2025-04-03 19:25:25 +0200 | [diff] [blame] | 61 | PointerAlignInBytes = |
| 62 | astContext |
| 63 | .toCharUnitsFromBits( |
| 64 | astContext.getTargetInfo().getPointerAlign(LangAS::Default)) |
| 65 | .getQuantity(); |
| 66 | |
| 67 | // TODO(CIR): Should be updated once TypeSizeInfoAttr is upstreamed |
| 68 | const unsigned sizeTypeSize = |
| 69 | astContext.getTypeSize(astContext.getSignedSizeType()); |
| 70 | PtrDiffTy = |
| 71 | cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true); |
| 72 | |
Andy Kaylor | 75ea7ae | 2025-02-19 09:08:37 -0800 | [diff] [blame] | 73 | theModule->setAttr(cir::CIRDialect::getTripleAttrName(), |
| 74 | builder.getStringAttr(getTriple().str())); |
David Olsen | ffb19f4 | 2024-12-10 11:29:48 -0800 | [diff] [blame] | 75 | } |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 76 | |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 77 | CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t, |
| 78 | LValueBaseInfo *baseInfo) { |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 79 | assert(!cir::MissingFeatures::opTBAA()); |
| 80 | |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 81 | // FIXME: This duplicates logic in ASTContext::getTypeAlignIfKnown, but |
| 82 | // that doesn't return the information we need to compute baseInfo. |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 83 | |
| 84 | // Honor alignment typedef attributes even on incomplete types. |
| 85 | // We also honor them straight for C++ class types, even as pointees; |
| 86 | // there's an expressivity gap here. |
| 87 | if (const auto *tt = t->getAs<TypedefType>()) { |
| 88 | if (unsigned align = tt->getDecl()->getMaxAlignment()) { |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 89 | if (baseInfo) |
| 90 | *baseInfo = LValueBaseInfo(AlignmentSource::AttributedType); |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 91 | return astContext.toCharUnitsFromBits(align); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // Analyze the base element type, so we don't get confused by incomplete |
| 96 | // array types. |
| 97 | t = astContext.getBaseElementType(t); |
| 98 | |
| 99 | if (t->isIncompleteType()) { |
| 100 | // We could try to replicate the logic from |
| 101 | // ASTContext::getTypeAlignIfKnown, but nothing uses the alignment if the |
| 102 | // type is incomplete, so it's impossible to test. We could try to reuse |
| 103 | // getTypeAlignIfKnown, but that doesn't return the information we need |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 104 | // to set baseInfo. So just ignore the possibility that the alignment is |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 105 | // greater than one. |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 106 | if (baseInfo) |
| 107 | *baseInfo = LValueBaseInfo(AlignmentSource::Type); |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 108 | return CharUnits::One(); |
| 109 | } |
| 110 | |
Andy Kaylor | 58b91d1 | 2025-04-09 15:27:50 -0700 | [diff] [blame] | 111 | if (baseInfo) |
| 112 | *baseInfo = LValueBaseInfo(AlignmentSource::Type); |
Andy Kaylor | 4928093 | 2025-04-08 10:32:03 -0700 | [diff] [blame] | 113 | |
| 114 | CharUnits alignment; |
| 115 | if (t.getQualifiers().hasUnaligned()) { |
| 116 | alignment = CharUnits::One(); |
| 117 | } else { |
| 118 | assert(!cir::MissingFeatures::alignCXXRecordDecl()); |
| 119 | alignment = astContext.getTypeAlignInChars(t); |
| 120 | } |
| 121 | |
| 122 | // Cap to the global maximum type alignment unless the alignment |
| 123 | // was somehow explicit on the type. |
| 124 | if (unsigned maxAlign = astContext.getLangOpts().MaxTypeAlign) { |
| 125 | if (alignment.getQuantity() > maxAlign && |
| 126 | !astContext.isAlignmentRequired(t)) |
| 127 | alignment = CharUnits::fromQuantity(maxAlign); |
| 128 | } |
| 129 | return alignment; |
| 130 | } |
| 131 | |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 132 | mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { |
| 133 | assert(cLoc.isValid() && "expected valid source location"); |
David Olsen | 7eb73b9 | 2024-12-10 13:46:07 -0800 | [diff] [blame] | 134 | const SourceManager &sm = astContext.getSourceManager(); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 135 | PresumedLoc pLoc = sm.getPresumedLoc(cLoc); |
| 136 | StringRef filename = pLoc.getFilename(); |
| 137 | return mlir::FileLineColLoc::get(builder.getStringAttr(filename), |
| 138 | pLoc.getLine(), pLoc.getColumn()); |
| 139 | } |
| 140 | |
| 141 | mlir::Location CIRGenModule::getLoc(SourceRange cRange) { |
| 142 | assert(cRange.isValid() && "expected a valid source range"); |
| 143 | mlir::Location begin = getLoc(cRange.getBegin()); |
| 144 | mlir::Location end = getLoc(cRange.getEnd()); |
| 145 | mlir::Attribute metadata; |
| 146 | return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext()); |
| 147 | } |
| 148 | |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 149 | void CIRGenModule::emitGlobal(clang::GlobalDecl gd) { |
Erich Keane | 231aa30 | 2025-04-08 10:06:28 -0700 | [diff] [blame] | 150 | if (const auto *cd = dyn_cast<clang::OpenACCConstructDecl>(gd.getDecl())) { |
| 151 | emitGlobalOpenACCDecl(cd); |
| 152 | return; |
| 153 | } |
| 154 | |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 155 | const auto *global = cast<ValueDecl>(gd.getDecl()); |
| 156 | |
| 157 | if (const auto *fd = dyn_cast<FunctionDecl>(global)) { |
| 158 | // Update deferred annotations with the latest declaration if the function |
| 159 | // was already used or defined. |
| 160 | if (fd->hasAttr<AnnotateAttr>()) |
| 161 | errorNYI(fd->getSourceRange(), "deferredAnnotations"); |
| 162 | if (!fd->doesThisDeclarationHaveABody()) { |
| 163 | if (!fd->doesDeclarationForceExternallyVisibleDefinition()) |
| 164 | return; |
| 165 | |
| 166 | errorNYI(fd->getSourceRange(), |
| 167 | "function declaration that forces code gen"); |
| 168 | return; |
| 169 | } |
| 170 | } else { |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 171 | assert(cast<VarDecl>(global)->isFileVarDecl() && |
| 172 | "Cannot emit local var decl as global"); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | // TODO(CIR): Defer emitting some global definitions until later |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 176 | emitGlobalDefinition(gd); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 177 | } |
| 178 | |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 179 | void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, |
| 180 | mlir::Operation *op) { |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 181 | auto const *funcDecl = cast<FunctionDecl>(gd.getDecl()); |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 182 | if (funcDecl->getIdentifier() == nullptr) { |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 183 | errorNYI(funcDecl->getSourceRange().getBegin(), |
| 184 | "function definition with a non-identifier for a name"); |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 185 | return; |
| 186 | } |
| 187 | cir::FuncType funcType = |
| 188 | cast<cir::FuncType>(convertType(funcDecl->getType())); |
| 189 | |
| 190 | cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op); |
| 191 | if (!funcOp || funcOp.getFunctionType() != funcType) { |
| 192 | funcOp = getAddrOfFunction(gd, funcType, /*ForVTable=*/false, |
| 193 | /*DontDefer=*/true, ForDefinition); |
| 194 | } |
| 195 | |
| 196 | CIRGenFunction cgf(*this, builder); |
Sirui Mu | 85614e1 | 2025-04-10 22:41:00 +0800 | [diff] [blame^] | 197 | curCGF = &cgf; |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 198 | { |
| 199 | mlir::OpBuilder::InsertionGuard guard(builder); |
| 200 | cgf.generateCode(gd, funcOp, funcType); |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 201 | } |
Sirui Mu | 85614e1 | 2025-04-10 22:41:00 +0800 | [diff] [blame^] | 202 | curCGF = nullptr; |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, |
| 206 | bool isTentative) { |
Amr Hesham | 6aeae62 | 2025-03-19 21:29:37 +0100 | [diff] [blame] | 207 | const QualType astTy = vd->getType(); |
| 208 | const mlir::Type type = convertType(vd->getType()); |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 209 | if (clang::IdentifierInfo *identifier = vd->getIdentifier()) { |
| 210 | auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()), |
| 211 | identifier->getName(), type); |
David Olsen | 8e32959 | 2024-12-28 14:02:15 -0800 | [diff] [blame] | 212 | // TODO(CIR): This code for processing initial values is a placeholder |
| 213 | // until class ConstantEmitter is upstreamed and the code for processing |
| 214 | // constant expressions is filled out. Only the most basic handling of |
| 215 | // certain constant expressions is implemented for now. |
| 216 | const VarDecl *initDecl; |
| 217 | const Expr *initExpr = vd->getAnyInitializer(initDecl); |
Amr Hesham | 143c371 | 2025-03-31 19:41:29 +0200 | [diff] [blame] | 218 | mlir::Attribute initializer; |
David Olsen | 8e32959 | 2024-12-28 14:02:15 -0800 | [diff] [blame] | 219 | if (initExpr) { |
David Olsen | 8e32959 | 2024-12-28 14:02:15 -0800 | [diff] [blame] | 220 | if (APValue *value = initDecl->evaluateValue()) { |
Amr Hesham | 6aeae62 | 2025-03-19 21:29:37 +0100 | [diff] [blame] | 221 | ConstantEmitter emitter(*this); |
| 222 | initializer = emitter.tryEmitPrivateForMemory(*value, astTy); |
David Olsen | 8e32959 | 2024-12-28 14:02:15 -0800 | [diff] [blame] | 223 | } else { |
| 224 | errorNYI(initExpr->getSourceRange(), "non-constant initializer"); |
| 225 | } |
Amr Hesham | 143c371 | 2025-03-31 19:41:29 +0200 | [diff] [blame] | 226 | } else { |
| 227 | initializer = builder.getZeroInitAttr(convertType(astTy)); |
David Olsen | 8e32959 | 2024-12-28 14:02:15 -0800 | [diff] [blame] | 228 | } |
Morris Hafner | 710de09 | 2025-03-06 19:17:58 +0100 | [diff] [blame] | 229 | |
Amr Hesham | 143c371 | 2025-03-31 19:41:29 +0200 | [diff] [blame] | 230 | varOp.setInitialValueAttr(initializer); |
| 231 | |
Morris Hafner | 710de09 | 2025-03-06 19:17:58 +0100 | [diff] [blame] | 232 | // Set CIR's linkage type as appropriate. |
| 233 | cir::GlobalLinkageKind linkage = |
| 234 | getCIRLinkageVarDefinition(vd, /*IsConstant=*/false); |
| 235 | |
| 236 | // Set CIR linkage and DLL storage class. |
| 237 | varOp.setLinkage(linkage); |
| 238 | |
| 239 | if (linkage == cir::GlobalLinkageKind::CommonLinkage) |
| 240 | errorNYI(initExpr->getSourceRange(), "common linkage"); |
| 241 | |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 242 | theModule.push_back(varOp); |
| 243 | } else { |
| 244 | errorNYI(vd->getSourceRange().getBegin(), |
| 245 | "variable definition with a non-identifier for a name"); |
| 246 | } |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 247 | } |
| 248 | |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 249 | void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, |
| 250 | mlir::Operation *op) { |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 251 | const auto *decl = cast<ValueDecl>(gd.getDecl()); |
| 252 | if (const auto *fd = dyn_cast<FunctionDecl>(decl)) { |
| 253 | // TODO(CIR): Skip generation of CIR for functions with available_externally |
| 254 | // linkage at -O0. |
| 255 | |
| 256 | if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) { |
| 257 | // Make sure to emit the definition(s) before we emit the thunks. This is |
| 258 | // necessary for the generation of certain thunks. |
| 259 | (void)method; |
| 260 | errorNYI(method->getSourceRange(), "member function"); |
| 261 | return; |
| 262 | } |
| 263 | |
| 264 | if (fd->isMultiVersion()) |
| 265 | errorNYI(fd->getSourceRange(), "multiversion functions"); |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 266 | emitGlobalFunctionDefinition(gd, op); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 267 | return; |
| 268 | } |
| 269 | |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 270 | if (const auto *vd = dyn_cast<VarDecl>(decl)) |
| 271 | return emitGlobalVarDefinition(vd, !vd->hasDefinition()); |
| 272 | |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 273 | llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition"); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 274 | } |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 275 | |
Morris Hafner | 710de09 | 2025-03-06 19:17:58 +0100 | [diff] [blame] | 276 | static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) { |
| 277 | assert(!cir::MissingFeatures::supportComdat()); |
| 278 | |
| 279 | if (d.hasAttr<SelectAnyAttr>()) |
| 280 | return true; |
| 281 | |
| 282 | GVALinkage linkage; |
| 283 | if (auto *vd = dyn_cast<VarDecl>(&d)) |
| 284 | linkage = cgm.getASTContext().GetGVALinkageForVariable(vd); |
| 285 | else |
| 286 | linkage = |
| 287 | cgm.getASTContext().GetGVALinkageForFunction(cast<FunctionDecl>(&d)); |
| 288 | |
| 289 | switch (linkage) { |
| 290 | case clang::GVA_Internal: |
| 291 | case clang::GVA_AvailableExternally: |
| 292 | case clang::GVA_StrongExternal: |
| 293 | return false; |
| 294 | case clang::GVA_DiscardableODR: |
| 295 | case clang::GVA_StrongODR: |
| 296 | return true; |
| 297 | } |
| 298 | llvm_unreachable("No such linkage"); |
| 299 | } |
| 300 | |
| 301 | // TODO(CIR): this could be a common method between LLVM codegen. |
| 302 | static bool isVarDeclStrongDefinition(const ASTContext &astContext, |
| 303 | CIRGenModule &cgm, const VarDecl *vd, |
| 304 | bool noCommon) { |
| 305 | // Don't give variables common linkage if -fno-common was specified unless it |
| 306 | // was overridden by a NoCommon attribute. |
| 307 | if ((noCommon || vd->hasAttr<NoCommonAttr>()) && !vd->hasAttr<CommonAttr>()) |
| 308 | return true; |
| 309 | |
| 310 | // C11 6.9.2/2: |
| 311 | // A declaration of an identifier for an object that has file scope without |
| 312 | // an initializer, and without a storage-class specifier or with the |
| 313 | // storage-class specifier static, constitutes a tentative definition. |
| 314 | if (vd->getInit() || vd->hasExternalStorage()) |
| 315 | return true; |
| 316 | |
| 317 | // A variable cannot be both common and exist in a section. |
| 318 | if (vd->hasAttr<SectionAttr>()) |
| 319 | return true; |
| 320 | |
| 321 | // A variable cannot be both common and exist in a section. |
| 322 | // We don't try to determine which is the right section in the front-end. |
| 323 | // If no specialized section name is applicable, it will resort to default. |
| 324 | if (vd->hasAttr<PragmaClangBSSSectionAttr>() || |
| 325 | vd->hasAttr<PragmaClangDataSectionAttr>() || |
| 326 | vd->hasAttr<PragmaClangRelroSectionAttr>() || |
| 327 | vd->hasAttr<PragmaClangRodataSectionAttr>()) |
| 328 | return true; |
| 329 | |
| 330 | // Thread local vars aren't considered common linkage. |
| 331 | if (vd->getTLSKind()) |
| 332 | return true; |
| 333 | |
| 334 | // Tentative definitions marked with WeakImportAttr are true definitions. |
| 335 | if (vd->hasAttr<WeakImportAttr>()) |
| 336 | return true; |
| 337 | |
| 338 | // A variable cannot be both common and exist in a comdat. |
| 339 | if (shouldBeInCOMDAT(cgm, *vd)) |
| 340 | return true; |
| 341 | |
| 342 | // Declarations with a required alignment do not have common linkage in MSVC |
| 343 | // mode. |
| 344 | if (astContext.getTargetInfo().getCXXABI().isMicrosoft()) { |
| 345 | if (vd->hasAttr<AlignedAttr>()) |
| 346 | return true; |
| 347 | QualType varType = vd->getType(); |
| 348 | if (astContext.isAlignmentRequired(varType)) |
| 349 | return true; |
| 350 | |
| 351 | if (const auto *rt = varType->getAs<RecordType>()) { |
| 352 | const RecordDecl *rd = rt->getDecl(); |
| 353 | for (const FieldDecl *fd : rd->fields()) { |
| 354 | if (fd->isBitField()) |
| 355 | continue; |
| 356 | if (fd->hasAttr<AlignedAttr>()) |
| 357 | return true; |
| 358 | if (astContext.isAlignmentRequired(fd->getType())) |
| 359 | return true; |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | // Microsoft's link.exe doesn't support alignments greater than 32 bytes for |
| 365 | // common symbols, so symbols with greater alignment requirements cannot be |
| 366 | // common. |
| 367 | // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two |
| 368 | // alignments for common symbols via the aligncomm directive, so this |
| 369 | // restriction only applies to MSVC environments. |
| 370 | if (astContext.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() && |
| 371 | astContext.getTypeAlignIfKnown(vd->getType()) > |
| 372 | astContext.toBits(CharUnits::fromQuantity(32))) |
| 373 | return true; |
| 374 | |
| 375 | return false; |
| 376 | } |
| 377 | |
| 378 | cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator( |
| 379 | const DeclaratorDecl *dd, GVALinkage linkage, bool isConstantVariable) { |
| 380 | if (linkage == GVA_Internal) |
| 381 | return cir::GlobalLinkageKind::InternalLinkage; |
| 382 | |
| 383 | if (dd->hasAttr<WeakAttr>()) { |
| 384 | if (isConstantVariable) |
| 385 | return cir::GlobalLinkageKind::WeakODRLinkage; |
| 386 | return cir::GlobalLinkageKind::WeakAnyLinkage; |
| 387 | } |
| 388 | |
| 389 | if (const auto *fd = dd->getAsFunction()) |
| 390 | if (fd->isMultiVersion() && linkage == GVA_AvailableExternally) |
| 391 | return cir::GlobalLinkageKind::LinkOnceAnyLinkage; |
| 392 | |
| 393 | // We are guaranteed to have a strong definition somewhere else, |
| 394 | // so we can use available_externally linkage. |
| 395 | if (linkage == GVA_AvailableExternally) |
| 396 | return cir::GlobalLinkageKind::AvailableExternallyLinkage; |
| 397 | |
| 398 | // Note that Apple's kernel linker doesn't support symbol |
| 399 | // coalescing, so we need to avoid linkonce and weak linkages there. |
| 400 | // Normally, this means we just map to internal, but for explicit |
| 401 | // instantiations we'll map to external. |
| 402 | |
| 403 | // In C++, the compiler has to emit a definition in every translation unit |
| 404 | // that references the function. We should use linkonce_odr because |
| 405 | // a) if all references in this translation unit are optimized away, we |
| 406 | // don't need to codegen it. b) if the function persists, it needs to be |
| 407 | // merged with other definitions. c) C++ has the ODR, so we know the |
| 408 | // definition is dependable. |
| 409 | if (linkage == GVA_DiscardableODR) |
| 410 | return !astContext.getLangOpts().AppleKext |
| 411 | ? cir::GlobalLinkageKind::LinkOnceODRLinkage |
| 412 | : cir::GlobalLinkageKind::InternalLinkage; |
| 413 | |
| 414 | // An explicit instantiation of a template has weak linkage, since |
| 415 | // explicit instantiations can occur in multiple translation units |
| 416 | // and must all be equivalent. However, we are not allowed to |
| 417 | // throw away these explicit instantiations. |
| 418 | // |
| 419 | // CUDA/HIP: For -fno-gpu-rdc case, device code is limited to one TU, |
| 420 | // so say that CUDA templates are either external (for kernels) or internal. |
| 421 | // This lets llvm perform aggressive inter-procedural optimizations. For |
| 422 | // -fgpu-rdc case, device function calls across multiple TU's are allowed, |
| 423 | // therefore we need to follow the normal linkage paradigm. |
| 424 | if (linkage == GVA_StrongODR) { |
| 425 | if (getLangOpts().AppleKext) |
| 426 | return cir::GlobalLinkageKind::ExternalLinkage; |
| 427 | if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice && |
| 428 | !getLangOpts().GPURelocatableDeviceCode) |
| 429 | return dd->hasAttr<CUDAGlobalAttr>() |
| 430 | ? cir::GlobalLinkageKind::ExternalLinkage |
| 431 | : cir::GlobalLinkageKind::InternalLinkage; |
| 432 | return cir::GlobalLinkageKind::WeakODRLinkage; |
| 433 | } |
| 434 | |
| 435 | // C++ doesn't have tentative definitions and thus cannot have common |
| 436 | // linkage. |
| 437 | if (!getLangOpts().CPlusPlus && isa<VarDecl>(dd) && |
| 438 | !isVarDeclStrongDefinition(astContext, *this, cast<VarDecl>(dd), |
| 439 | getCodeGenOpts().NoCommon)) { |
| 440 | errorNYI(dd->getBeginLoc(), "common linkage", dd->getDeclKindName()); |
| 441 | return cir::GlobalLinkageKind::CommonLinkage; |
| 442 | } |
| 443 | |
| 444 | // selectany symbols are externally visible, so use weak instead of |
| 445 | // linkonce. MSVC optimizes away references to const selectany globals, so |
| 446 | // all definitions should be the same and ODR linkage should be used. |
| 447 | // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx |
| 448 | if (dd->hasAttr<SelectAnyAttr>()) |
| 449 | return cir::GlobalLinkageKind::WeakODRLinkage; |
| 450 | |
| 451 | // Otherwise, we have strong external linkage. |
| 452 | assert(linkage == GVA_StrongExternal); |
| 453 | return cir::GlobalLinkageKind::ExternalLinkage; |
| 454 | } |
| 455 | |
| 456 | cir::GlobalLinkageKind |
| 457 | CIRGenModule::getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant) { |
| 458 | assert(!isConstant && "constant variables NYI"); |
| 459 | GVALinkage linkage = astContext.GetGVALinkageForVariable(vd); |
| 460 | return getCIRLinkageForDeclarator(vd, linkage, isConstant); |
| 461 | } |
| 462 | |
Nathan Lanza | 1bb52e9 | 2024-10-09 14:20:50 -0400 | [diff] [blame] | 463 | // Emit code for a single top level declaration. |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 464 | void CIRGenModule::emitTopLevelDecl(Decl *decl) { |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 465 | |
| 466 | // Ignore dependent declarations. |
| 467 | if (decl->isTemplated()) |
| 468 | return; |
| 469 | |
| 470 | switch (decl->getKind()) { |
| 471 | default: |
| 472 | errorNYI(decl->getBeginLoc(), "declaration of kind", |
| 473 | decl->getDeclKindName()); |
| 474 | break; |
| 475 | |
| 476 | case Decl::Function: { |
| 477 | auto *fd = cast<FunctionDecl>(decl); |
| 478 | // Consteval functions shouldn't be emitted. |
| 479 | if (!fd->isConsteval()) |
Shoaib Meenai | 1791b25 | 2024-11-12 09:56:25 -0800 | [diff] [blame] | 480 | emitGlobal(fd); |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 481 | break; |
| 482 | } |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 483 | |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 484 | case Decl::Var: { |
| 485 | auto *vd = cast<VarDecl>(decl); |
| 486 | emitGlobal(vd); |
| 487 | break; |
| 488 | } |
Erich Keane | 231aa30 | 2025-04-08 10:06:28 -0700 | [diff] [blame] | 489 | case Decl::OpenACCRoutine: |
| 490 | emitGlobalOpenACCDecl(cast<OpenACCRoutineDecl>(decl)); |
| 491 | break; |
| 492 | case Decl::OpenACCDeclare: |
| 493 | emitGlobalOpenACCDecl(cast<OpenACCDeclareDecl>(decl)); |
| 494 | break; |
David Olsen | a43b2e1 | 2024-12-06 07:01:09 -0800 | [diff] [blame] | 495 | } |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 496 | } |
| 497 | |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 498 | cir::FuncOp CIRGenModule::getAddrOfFunction(clang::GlobalDecl gd, |
| 499 | mlir::Type funcType, bool forVTable, |
| 500 | bool dontDefer, |
| 501 | ForDefinition_t isForDefinition) { |
| 502 | assert(!cast<FunctionDecl>(gd.getDecl())->isConsteval() && |
| 503 | "consteval function should never be emitted"); |
| 504 | |
| 505 | if (!funcType) { |
| 506 | const auto *fd = cast<FunctionDecl>(gd.getDecl()); |
| 507 | funcType = convertType(fd->getType()); |
| 508 | } |
| 509 | |
| 510 | cir::FuncOp func = getOrCreateCIRFunction( |
| 511 | cast<NamedDecl>(gd.getDecl())->getIdentifier()->getName(), funcType, gd, |
| 512 | forVTable, dontDefer, /*isThunk=*/false, isForDefinition); |
| 513 | return func; |
| 514 | } |
| 515 | |
| 516 | cir::FuncOp CIRGenModule::getOrCreateCIRFunction( |
| 517 | StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable, |
| 518 | bool dontDefer, bool isThunk, ForDefinition_t isForDefinition, |
| 519 | mlir::ArrayAttr extraAttrs) { |
| 520 | auto *funcDecl = llvm::cast_or_null<FunctionDecl>(gd.getDecl()); |
| 521 | bool invalidLoc = !funcDecl || |
| 522 | funcDecl->getSourceRange().getBegin().isInvalid() || |
| 523 | funcDecl->getSourceRange().getEnd().isInvalid(); |
| 524 | cir::FuncOp funcOp = createCIRFunction( |
| 525 | invalidLoc ? theModule->getLoc() : getLoc(funcDecl->getSourceRange()), |
| 526 | mangledName, mlir::cast<cir::FuncType>(funcType), funcDecl); |
| 527 | return funcOp; |
| 528 | } |
| 529 | |
| 530 | cir::FuncOp |
| 531 | CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, |
| 532 | cir::FuncType funcType, |
| 533 | const clang::FunctionDecl *funcDecl) { |
| 534 | cir::FuncOp func; |
| 535 | { |
| 536 | mlir::OpBuilder::InsertionGuard guard(builder); |
| 537 | |
Sirui Mu | 85614e1 | 2025-04-10 22:41:00 +0800 | [diff] [blame^] | 538 | // Some global emissions are triggered while emitting a function, e.g. |
| 539 | // void s() { x.method() } |
| 540 | // |
| 541 | // Be sure to insert a new function before a current one. |
| 542 | CIRGenFunction *cgf = this->curCGF; |
| 543 | if (cgf) |
| 544 | builder.setInsertionPoint(cgf->curFn); |
| 545 | |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 546 | func = builder.create<cir::FuncOp>(loc, name, funcType); |
Sirui Mu | 85614e1 | 2025-04-10 22:41:00 +0800 | [diff] [blame^] | 547 | |
| 548 | if (!cgf) |
| 549 | theModule.push_back(func); |
David Olsen | f8bdbed | 2025-02-19 19:58:12 -0800 | [diff] [blame] | 550 | } |
| 551 | return func; |
| 552 | } |
| 553 | |
| 554 | mlir::Type CIRGenModule::convertType(QualType type) { |
| 555 | return genTypes.convertType(type); |
| 556 | } |
| 557 | |
Andy Kaylor | 39ce995 | 2025-03-19 09:42:03 -0700 | [diff] [blame] | 558 | bool CIRGenModule::verifyModule() const { |
| 559 | // Verify the module after we have finished constructing it, this will |
| 560 | // check the structural properties of the IR and invoke any specific |
| 561 | // verifiers we have on the CIR operations. |
| 562 | return mlir::verify(theModule).succeeded(); |
| 563 | } |
| 564 | |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 565 | DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, |
| 566 | llvm::StringRef feature) { |
| 567 | unsigned diagID = diags.getCustomDiagID( |
| 568 | DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); |
| 569 | return diags.Report(loc, diagID) << feature; |
| 570 | } |
| 571 | |
David Olsen | c695a32 | 2024-11-05 11:16:30 -0800 | [diff] [blame] | 572 | DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, |
| 573 | llvm::StringRef feature) { |
| 574 | return errorNYI(loc.getBegin(), feature) << loc; |
| 575 | } |