1//===----------------------------------------------------------------------===//
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// Internal per-function state used for AST-to-ClangIR code gen
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenFunction.h"
14
15#include "CIRGenCXXABI.h"
16#include "CIRGenCall.h"
17#include "CIRGenValue.h"
18#include "mlir/IR/Location.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/GlobalDecl.h"
21#include "clang/CIR/MissingFeatures.h"
22
23#include <cassert>
24
25namespace clang::CIRGen {
26
27CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,
28 bool suppressNewContext)
29 : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {}
30
31CIRGenFunction::~CIRGenFunction() {}
32
33// This is copied from clang/lib/CodeGen/CodeGenFunction.cpp
34cir::TypeEvaluationKind CIRGenFunction::getEvaluationKind(QualType type) {
35 type = type.getCanonicalType();
36 while (true) {
37 switch (type->getTypeClass()) {
38#define TYPE(name, parent)
39#define ABSTRACT_TYPE(name, parent)
40#define NON_CANONICAL_TYPE(name, parent) case Type::name:
41#define DEPENDENT_TYPE(name, parent) case Type::name:
42#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
43#include "clang/AST/TypeNodes.inc"
44 llvm_unreachable("non-canonical or dependent type in IR-generation");
45
46 case Type::Auto:
47 case Type::DeducedTemplateSpecialization:
48 llvm_unreachable("undeduced type in IR-generation");
49
50 // Various scalar types.
51 case Type::Builtin:
52 case Type::Pointer:
53 case Type::BlockPointer:
54 case Type::LValueReference:
55 case Type::RValueReference:
56 case Type::MemberPointer:
57 case Type::Vector:
58 case Type::ExtVector:
59 case Type::ConstantMatrix:
60 case Type::FunctionProto:
61 case Type::FunctionNoProto:
62 case Type::Enum:
63 case Type::ObjCObjectPointer:
64 case Type::Pipe:
65 case Type::BitInt:
66 case Type::HLSLAttributedResource:
67 case Type::HLSLInlineSpirv:
68 return cir::TEK_Scalar;
69
70 // Complexes.
71 case Type::Complex:
72 return cir::TEK_Complex;
73
74 // Arrays, records, and Objective-C objects.
75 case Type::ConstantArray:
76 case Type::IncompleteArray:
77 case Type::VariableArray:
78 case Type::Record:
79 case Type::ObjCObject:
80 case Type::ObjCInterface:
81 case Type::ArrayParameter:
82 return cir::TEK_Aggregate;
83
84 // We operate on atomic values according to their underlying type.
85 case Type::Atomic:
86 type = cast<AtomicType>(Val&: type)->getValueType();
87 continue;
88 }
89 llvm_unreachable("unknown type kind!");
90 }
91}
92
93mlir::Type CIRGenFunction::convertTypeForMem(QualType t) {
94 return cgm.getTypes().convertTypeForMem(t);
95}
96
97mlir::Type CIRGenFunction::convertType(QualType t) {
98 return cgm.getTypes().convertType(t);
99}
100
101mlir::Location CIRGenFunction::getLoc(SourceLocation srcLoc) {
102 // Some AST nodes might contain invalid source locations (e.g.
103 // CXXDefaultArgExpr), workaround that to still get something out.
104 if (srcLoc.isValid()) {
105 const SourceManager &sm = getContext().getSourceManager();
106 PresumedLoc pLoc = sm.getPresumedLoc(Loc: srcLoc);
107 StringRef filename = pLoc.getFilename();
108 return mlir::FileLineColLoc::get(builder.getStringAttr(filename),
109 pLoc.getLine(), pLoc.getColumn());
110 }
111 // Do our best...
112 assert(currSrcLoc && "expected to inherit some source location");
113 return *currSrcLoc;
114}
115
116mlir::Location CIRGenFunction::getLoc(SourceRange srcLoc) {
117 // Some AST nodes might contain invalid source locations (e.g.
118 // CXXDefaultArgExpr), workaround that to still get something out.
119 if (srcLoc.isValid()) {
120 mlir::Location beg = getLoc(srcLoc.getBegin());
121 mlir::Location end = getLoc(srcLoc.getEnd());
122 SmallVector<mlir::Location, 2> locs = {beg, end};
123 mlir::Attribute metadata;
124 return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());
125 }
126 if (currSrcLoc) {
127 return *currSrcLoc;
128 }
129 // We're brave, but time to give up.
130 return builder.getUnknownLoc();
131}
132
133mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, mlir::Location rhs) {
134 SmallVector<mlir::Location, 2> locs = {lhs, rhs};
135 mlir::Attribute metadata;
136 return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());
137}
138
139bool CIRGenFunction::containsLabel(const Stmt *s, bool ignoreCaseStmts) {
140 // Null statement, not a label!
141 if (!s)
142 return false;
143
144 // If this is a label, we have to emit the code, consider something like:
145 // if (0) { ... foo: bar(); } goto foo;
146 //
147 // TODO: If anyone cared, we could track __label__'s, since we know that you
148 // can't jump to one from outside their declared region.
149 if (isa<LabelStmt>(Val: s))
150 return true;
151
152 // If this is a case/default statement, and we haven't seen a switch, we
153 // have to emit the code.
154 if (isa<SwitchCase>(Val: s) && !ignoreCaseStmts)
155 return true;
156
157 // If this is a switch statement, we want to ignore case statements when we
158 // recursively process the sub-statements of the switch. If we haven't
159 // encountered a switch statement, we treat case statements like labels, but
160 // if we are processing a switch statement, case statements are expected.
161 if (isa<SwitchStmt>(Val: s))
162 ignoreCaseStmts = true;
163
164 // Scan subexpressions for verboten labels.
165 return std::any_of(first: s->child_begin(), last: s->child_end(),
166 pred: [=](const Stmt *subStmt) {
167 return containsLabel(s: subStmt, ignoreCaseStmts);
168 });
169}
170
171/// If the specified expression does not fold to a constant, or if it does but
172/// contains a label, return false. If it constant folds return true and set
173/// the boolean result in Result.
174bool CIRGenFunction::constantFoldsToBool(const Expr *cond, bool &resultBool,
175 bool allowLabels) {
176 llvm::APSInt resultInt;
177 if (!constantFoldsToSimpleInteger(cond, resultInt, allowLabels))
178 return false;
179
180 resultBool = resultInt.getBoolValue();
181 return true;
182}
183
184/// If the specified expression does not fold to a constant, or if it does
185/// fold but contains a label, return false. If it constant folds, return
186/// true and set the folded value.
187bool CIRGenFunction::constantFoldsToSimpleInteger(const Expr *cond,
188 llvm::APSInt &resultInt,
189 bool allowLabels) {
190 // FIXME: Rename and handle conversion of other evaluatable things
191 // to bool.
192 Expr::EvalResult result;
193 if (!cond->EvaluateAsInt(Result&: result, Ctx: getContext()))
194 return false; // Not foldable, not integer or not fully evaluatable.
195
196 llvm::APSInt intValue = result.Val.getInt();
197 if (!allowLabels && containsLabel(s: cond))
198 return false; // Contains a label.
199
200 resultInt = intValue;
201 return true;
202}
203
204void CIRGenFunction::emitAndUpdateRetAlloca(QualType type, mlir::Location loc,
205 CharUnits alignment) {
206 if (!type->isVoidType()) {
207 fnRetAlloca = emitAlloca("__retval", convertType(type), loc, alignment,
208 /*insertIntoFnEntryBlock=*/false);
209 }
210}
211
212void CIRGenFunction::declare(mlir::Value addrVal, const Decl *var, QualType ty,
213 mlir::Location loc, CharUnits alignment,
214 bool isParam) {
215 const auto *namedVar = dyn_cast_or_null<NamedDecl>(Val: var);
216 assert(namedVar && "Needs a named decl");
217 assert(!cir::MissingFeatures::cgfSymbolTable());
218
219 auto allocaOp = cast<cir::AllocaOp>(addrVal.getDefiningOp());
220 if (isParam)
221 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
222 if (ty->isReferenceType() || ty.isConstQualified())
223 allocaOp.setConstantAttr(mlir::UnitAttr::get(&getMLIRContext()));
224}
225
226void CIRGenFunction::LexicalScope::cleanup() {
227 CIRGenBuilderTy &builder = cgf.builder;
228 LexicalScope *localScope = cgf.curLexScope;
229
230 if (returnBlock != nullptr) {
231 // Write out the return block, which loads the value from `__retval` and
232 // issues the `cir.return`.
233 mlir::OpBuilder::InsertionGuard guard(builder);
234 builder.setInsertionPointToEnd(returnBlock);
235 (void)emitReturn(*returnLoc);
236 }
237
238 mlir::Block *curBlock = builder.getBlock();
239 if (isGlobalInit() && !curBlock)
240 return;
241 if (curBlock->mightHaveTerminator() && curBlock->getTerminator())
242 return;
243
244 // Get rid of any empty block at the end of the scope.
245 bool entryBlock = builder.getInsertionBlock()->isEntryBlock();
246 if (!entryBlock && curBlock->empty()) {
247 curBlock->erase();
248 if (returnBlock != nullptr && returnBlock->getUses().empty())
249 returnBlock->erase();
250 return;
251 }
252
253 // Reached the end of the scope.
254 {
255 mlir::OpBuilder::InsertionGuard guard(builder);
256 builder.setInsertionPointToEnd(curBlock);
257
258 if (localScope->depth == 0) {
259 // Reached the end of the function.
260 if (returnBlock != nullptr) {
261 if (returnBlock->getUses().empty())
262 returnBlock->erase();
263 else {
264 builder.create<cir::BrOp>(*returnLoc, returnBlock);
265 return;
266 }
267 }
268 emitImplicitReturn();
269 return;
270 }
271 // Reached the end of a non-function scope. Some scopes, such as those
272 // used with the ?: operator, can return a value.
273 if (!localScope->isTernary() && !curBlock->mightHaveTerminator()) {
274 !retVal ? builder.create<cir::YieldOp>(localScope->endLoc)
275 : builder.create<cir::YieldOp>(localScope->endLoc, retVal);
276 }
277 }
278}
279
280cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
281 CIRGenBuilderTy &builder = cgf.getBuilder();
282
283 if (!cgf.curFn.getFunctionType().hasVoidReturn()) {
284 // Load the value from `__retval` and return it via the `cir.return` op.
285 auto value = builder.create<cir::LoadOp>(
286 loc, cgf.curFn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);
287 return builder.create<cir::ReturnOp>(loc,
288 llvm::ArrayRef(value.getResult()));
289 }
290 return builder.create<cir::ReturnOp>(loc);
291}
292
293// This is copied from CodeGenModule::MayDropFunctionReturn. This is a
294// candidate for sharing between CIRGen and CodeGen.
295static bool mayDropFunctionReturn(const ASTContext &astContext,
296 QualType returnType) {
297 // We can't just discard the return value for a record type with a complex
298 // destructor or a non-trivially copyable type.
299 if (const RecordType *recordType =
300 returnType.getCanonicalType()->getAs<RecordType>()) {
301 if (const auto *classDecl = dyn_cast<CXXRecordDecl>(Val: recordType->getDecl()))
302 return classDecl->hasTrivialDestructor();
303 }
304 return returnType.isTriviallyCopyableType(Context: astContext);
305}
306
307void CIRGenFunction::LexicalScope::emitImplicitReturn() {
308 CIRGenBuilderTy &builder = cgf.getBuilder();
309 LexicalScope *localScope = cgf.curLexScope;
310
311 const auto *fd = cast<clang::FunctionDecl>(Val: cgf.curGD.getDecl());
312
313 // In C++, flowing off the end of a non-void function is always undefined
314 // behavior. In C, flowing off the end of a non-void function is undefined
315 // behavior only if the non-existent return value is used by the caller.
316 // That influences whether the terminating op is trap, unreachable, or
317 // return.
318 if (cgf.getLangOpts().CPlusPlus && !fd->hasImplicitReturnZero() &&
319 !cgf.sawAsmBlock && !fd->getReturnType()->isVoidType() &&
320 builder.getInsertionBlock()) {
321 bool shouldEmitUnreachable =
322 cgf.cgm.getCodeGenOpts().StrictReturn ||
323 !mayDropFunctionReturn(astContext: fd->getASTContext(), returnType: fd->getReturnType());
324
325 if (shouldEmitUnreachable) {
326 if (cgf.cgm.getCodeGenOpts().OptimizationLevel == 0)
327 builder.create<cir::TrapOp>(localScope->endLoc);
328 else
329 builder.create<cir::UnreachableOp>(localScope->endLoc);
330 builder.clearInsertionPoint();
331 return;
332 }
333 }
334
335 (void)emitReturn(localScope->endLoc);
336}
337
338void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
339 cir::FuncOp fn, cir::FuncType funcType,
340 FunctionArgList args, SourceLocation loc,
341 SourceLocation startLoc) {
342 assert(!curFn &&
343 "CIRGenFunction can only be used for one function at a time");
344
345 curFn = fn;
346
347 const Decl *d = gd.getDecl();
348 const auto *fd = dyn_cast_or_null<FunctionDecl>(Val: d);
349 curFuncDecl = d->getNonClosureContext();
350
351 mlir::Block *entryBB = &fn.getBlocks().front();
352 builder.setInsertionPointToStart(entryBB);
353
354 // TODO(cir): this should live in `emitFunctionProlog
355 // Declare all the function arguments in the symbol table.
356 for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
357 const VarDecl *paramVar = std::get<0>(nameValue);
358 mlir::Value paramVal = std::get<1>(nameValue);
359 CharUnits alignment = getContext().getDeclAlign(paramVar);
360 mlir::Location paramLoc = getLoc(paramVar->getSourceRange());
361 paramVal.setLoc(paramLoc);
362
363 mlir::Value addrVal =
364 emitAlloca(cast<NamedDecl>(paramVar)->getName(),
365 convertType(paramVar->getType()), paramLoc, alignment,
366 /*insertIntoFnEntryBlock=*/true);
367
368 declare(addrVal, paramVar, paramVar->getType(), paramLoc, alignment,
369 /*isParam=*/true);
370
371 setAddrOfLocalVar(paramVar, Address(addrVal, alignment));
372
373 bool isPromoted = isa<ParmVarDecl>(paramVar) &&
374 cast<ParmVarDecl>(paramVar)->isKNRPromoted();
375 assert(!cir::MissingFeatures::constructABIArgDirectExtend());
376 if (isPromoted)
377 cgm.errorNYI(fd->getSourceRange(), "Function argument demotion");
378
379 // Location of the store to the param storage tracked as beginning of
380 // the function body.
381 mlir::Location fnBodyBegin = getLoc(fd->getBody()->getBeginLoc());
382 builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);
383 }
384 assert(builder.getInsertionBlock() && "Should be valid");
385
386 // When the current function is not void, create an address to store the
387 // result value.
388 if (!returnType->isVoidType())
389 emitAndUpdateRetAlloca(returnType, getLoc(fd->getBody()->getEndLoc()),
390 getContext().getTypeAlignInChars(returnType));
391
392 if (isa_and_nonnull<CXXMethodDecl>(Val: d) &&
393 cast<CXXMethodDecl>(Val: d)->isInstance()) {
394 cgm.getCXXABI().emitInstanceFunctionProlog(Loc: loc, cgf&: *this);
395
396 const auto *md = cast<CXXMethodDecl>(Val: d);
397 if (md->getParent()->isLambda() && md->getOverloadedOperator() == OO_Call) {
398 cgm.errorNYI(loc, "lambda call operator");
399 } else {
400 // Not in a lambda; just use 'this' from the method.
401 // FIXME: Should we generate a new load for each use of 'this'? The fast
402 // register allocator would be happier...
403 cxxThisValue = cxxabiThisValue;
404 }
405
406 assert(!cir::MissingFeatures::sanitizers());
407 assert(!cir::MissingFeatures::emitTypeCheck());
408 }
409}
410
411void CIRGenFunction::finishFunction(SourceLocation endLoc) {}
412
413mlir::LogicalResult CIRGenFunction::emitFunctionBody(const clang::Stmt *body) {
414 auto result = mlir::LogicalResult::success();
415 if (const CompoundStmt *block = dyn_cast<CompoundStmt>(Val: body))
416 emitCompoundStmtWithoutScope(s: *block);
417 else
418 result = emitStmt(body, /*useCurrentScope=*/true);
419
420 return result;
421}
422
423static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
424 // Remove any leftover blocks that are unreachable and empty, since they do
425 // not represent unreachable code useful for warnings nor anything deemed
426 // useful in general.
427 SmallVector<mlir::Block *> blocksToDelete;
428 for (mlir::Block &block : func.getBlocks()) {
429 if (block.empty() && block.getUses().empty())
430 blocksToDelete.push_back(&block);
431 }
432 for (mlir::Block *block : blocksToDelete)
433 block->erase();
434}
435
436cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
437 cir::FuncType funcType) {
438 const auto funcDecl = cast<FunctionDecl>(Val: gd.getDecl());
439 curGD = gd;
440
441 SourceLocation loc = funcDecl->getLocation();
442 Stmt *body = funcDecl->getBody();
443 SourceRange bodyRange =
444 body ? body->getSourceRange() : funcDecl->getLocation();
445
446 SourceLocRAIIObject fnLoc{*this, loc.isValid() ? getLoc(loc)
447 : builder.getUnknownLoc()};
448
449 auto validMLIRLoc = [&](clang::SourceLocation clangLoc) {
450 return clangLoc.isValid() ? getLoc(clangLoc) : builder.getUnknownLoc();
451 };
452 const mlir::Location fusedLoc = mlir::FusedLoc::get(
453 &getMLIRContext(),
454 {validMLIRLoc(bodyRange.getBegin()), validMLIRLoc(bodyRange.getEnd())});
455 mlir::Block *entryBB = fn.addEntryBlock();
456
457 FunctionArgList args;
458 QualType retTy = buildFunctionArgList(gd, args);
459
460 {
461 LexicalScope lexScope(*this, fusedLoc, entryBB);
462
463 startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
464
465 if (isa<CXXDestructorDecl>(Val: funcDecl)) {
466 emitDestructorBody(args);
467 } else if (isa<CXXConstructorDecl>(Val: funcDecl)) {
468 emitConstructorBody(args);
469 } else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice &&
470 funcDecl->hasAttr<CUDAGlobalAttr>()) {
471 getCIRGenModule().errorNYI(bodyRange, "CUDA kernel");
472 } else if (isa<CXXMethodDecl>(Val: funcDecl) &&
473 cast<CXXMethodDecl>(Val: funcDecl)->isLambdaStaticInvoker()) {
474 getCIRGenModule().errorNYI(bodyRange, "Lambda static invoker");
475 } else if (funcDecl->isDefaulted() && isa<CXXMethodDecl>(Val: funcDecl) &&
476 (cast<CXXMethodDecl>(Val: funcDecl)->isCopyAssignmentOperator() ||
477 cast<CXXMethodDecl>(Val: funcDecl)->isMoveAssignmentOperator())) {
478 // Implicit copy-assignment gets the same special treatment as implicit
479 // copy-constructors.
480 emitImplicitAssignmentOperatorBody(args);
481 } else if (body) {
482 if (mlir::failed(emitFunctionBody(body))) {
483 fn.erase();
484 return nullptr;
485 }
486 } else {
487 // Anything without a body should have been handled above.
488 llvm_unreachable("no definition for normal function");
489 }
490
491 if (mlir::failed(fn.verifyBody()))
492 return nullptr;
493
494 finishFunction(endLoc: bodyRange.getEnd());
495 }
496
497 eraseEmptyAndUnusedBlocks(fn);
498 return fn;
499}
500
501void CIRGenFunction::emitConstructorBody(FunctionArgList &args) {
502 assert(!cir::MissingFeatures::sanitizers());
503 const auto *ctor = cast<CXXConstructorDecl>(Val: curGD.getDecl());
504 CXXCtorType ctorType = curGD.getCtorType();
505
506 assert((cgm.getTarget().getCXXABI().hasConstructorVariants() ||
507 ctorType == Ctor_Complete) &&
508 "can only generate complete ctor for this ABI");
509
510 if (ctorType == Ctor_Complete && isConstructorDelegationValid(ctor) &&
511 cgm.getTarget().getCXXABI().hasConstructorVariants()) {
512 emitDelegateCXXConstructorCall(ctor, ctorType: Ctor_Base, args, loc: ctor->getEndLoc());
513 return;
514 }
515
516 const FunctionDecl *definition = nullptr;
517 Stmt *body = ctor->getBody(Definition&: definition);
518 assert(definition == ctor && "emitting wrong constructor body");
519
520 if (isa_and_nonnull<CXXTryStmt>(Val: body)) {
521 cgm.errorNYI(ctor->getSourceRange(), "emitConstructorBody: try body");
522 return;
523 }
524
525 assert(!cir::MissingFeatures::incrementProfileCounter());
526 assert(!cir::MissingFeatures::runCleanupsScope());
527
528 // TODO: in restricted cases, we can emit the vbase initializers of a
529 // complete ctor and then delegate to the base ctor.
530
531 // Emit the constructor prologue, i.e. the base and member initializers.
532 emitCtorPrologue(ctor, ctorType, args);
533
534 // TODO(cir): propagate this result via mlir::logical result. Just unreachable
535 // now just to have it handled.
536 if (mlir::failed(emitStmt(body, true))) {
537 cgm.errorNYI(ctor->getSourceRange(),
538 "emitConstructorBody: emit body statement failed.");
539 return;
540 }
541}
542
543/// Emits the body of the current destructor.
544void CIRGenFunction::emitDestructorBody(FunctionArgList &args) {
545 const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(Val: curGD.getDecl());
546 CXXDtorType dtorType = curGD.getDtorType();
547
548 // For an abstract class, non-base destructors are never used (and can't
549 // be emitted in general, because vbase dtors may not have been validated
550 // by Sema), but the Itanium ABI doesn't make them optional and Clang may
551 // in fact emit references to them from other compilations, so emit them
552 // as functions containing a trap instruction.
553 if (dtorType != Dtor_Base && dtor->getParent()->isAbstract()) {
554 cgm.errorNYI(dtor->getSourceRange(), "abstract base class destructors");
555 return;
556 }
557
558 Stmt *body = dtor->getBody();
559 assert(body && !cir::MissingFeatures::incrementProfileCounter());
560
561 // The call to operator delete in a deleting destructor happens
562 // outside of the function-try-block, which means it's always
563 // possible to delegate the destructor body to the complete
564 // destructor. Do so.
565 if (dtorType == Dtor_Deleting) {
566 cgm.errorNYI(dtor->getSourceRange(), "deleting destructor");
567 return;
568 }
569
570 // If the body is a function-try-block, enter the try before
571 // anything else.
572 const bool isTryBody = isa_and_nonnull<CXXTryStmt>(Val: body);
573 if (isTryBody)
574 cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
575
576 assert(!cir::MissingFeatures::sanitizers());
577 assert(!cir::MissingFeatures::dtorCleanups());
578
579 // If this is the complete variant, just invoke the base variant;
580 // the epilogue will destruct the virtual bases. But we can't do
581 // this optimization if the body is a function-try-block, because
582 // we'd introduce *two* handler blocks. In the Microsoft ABI, we
583 // always delegate because we might not have a definition in this TU.
584 switch (dtorType) {
585 case Dtor_Comdat:
586 llvm_unreachable("not expecting a COMDAT");
587 case Dtor_Deleting:
588 llvm_unreachable("already handled deleting case");
589
590 case Dtor_Complete:
591 assert((body || getTarget().getCXXABI().isMicrosoft()) &&
592 "can't emit a dtor without a body for non-Microsoft ABIs");
593
594 assert(!cir::MissingFeatures::dtorCleanups());
595
596 // TODO(cir): A complete destructor is supposed to call the base destructor.
597 // Since we have to emit both dtor kinds we just fall through for now and.
598 // As long as we don't support virtual bases this should be functionally
599 // equivalent.
600 assert(!cir::MissingFeatures::completeDtors());
601
602 // Fallthrough: act like we're in the base variant.
603 [[fallthrough]];
604
605 case Dtor_Base:
606 assert(body);
607
608 assert(!cir::MissingFeatures::dtorCleanups());
609 assert(!cir::MissingFeatures::vtableInitialization());
610
611 if (isTryBody) {
612 cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
613 } else if (body) {
614 (void)emitStmt(body, /*useCurrentScope=*/true);
615 } else {
616 assert(dtor->isImplicit() && "bodyless dtor not implicit");
617 // nothing to do besides what's in the epilogue
618 }
619 // -fapple-kext must inline any call to this dtor into
620 // the caller's body.
621 assert(!cir::MissingFeatures::appleKext());
622
623 break;
624 }
625
626 assert(!cir::MissingFeatures::dtorCleanups());
627
628 // Exit the try if applicable.
629 if (isTryBody)
630 cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
631}
632
633/// Given a value of type T* that may not be to a complete object, construct
634/// an l-vlaue withi the natural pointee alignment of T.
635LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val,
636 QualType ty) {
637 // FIXME(cir): is it safe to assume Op->getResult(0) is valid? Perhaps
638 // assert on the result type first.
639 LValueBaseInfo baseInfo;
640 assert(!cir::MissingFeatures::opTBAA());
641 CharUnits align = cgm.getNaturalTypeAlignment(t: ty, baseInfo: &baseInfo);
642 return makeAddrLValue(addr: Address(val, align), ty, baseInfo);
643}
644
645LValue CIRGenFunction::makeNaturalAlignAddrLValue(mlir::Value val,
646 QualType ty) {
647 LValueBaseInfo baseInfo;
648 CharUnits alignment = cgm.getNaturalTypeAlignment(t: ty, baseInfo: &baseInfo);
649 Address addr(val, convertTypeForMem(ty), alignment);
650 assert(!cir::MissingFeatures::opTBAA());
651 return makeAddrLValue(addr, ty, baseInfo);
652}
653
654clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
655 FunctionArgList &args) {
656 const auto *fd = cast<FunctionDecl>(Val: gd.getDecl());
657 QualType retTy = fd->getReturnType();
658
659 const auto *md = dyn_cast<CXXMethodDecl>(Val: fd);
660 if (md && md->isInstance()) {
661 if (cgm.getCXXABI().hasThisReturn(gd))
662 cgm.errorNYI(fd->getSourceRange(), "this return");
663 else if (cgm.getCXXABI().hasMostDerivedReturn(gd))
664 cgm.errorNYI(fd->getSourceRange(), "most derived return");
665 cgm.getCXXABI().buildThisParam(cgf&: *this, params&: args);
666 }
667
668 if (const auto *cd = dyn_cast<CXXConstructorDecl>(Val: fd))
669 if (cd->getInheritedConstructor())
670 cgm.errorNYI(fd->getSourceRange(),
671 "buildFunctionArgList: inherited constructor");
672
673 for (auto *param : fd->parameters())
674 args.push_back(Elt: param);
675
676 if (md && (isa<CXXConstructorDecl>(Val: md) || isa<CXXDestructorDecl>(Val: md)))
677 assert(!cir::MissingFeatures::cxxabiStructorImplicitParam());
678
679 return retTy;
680}
681
682/// Emit code to compute a designator that specifies the location
683/// of the expression.
684/// FIXME: document this function better.
685LValue CIRGenFunction::emitLValue(const Expr *e) {
686 // FIXME: ApplyDebugLocation DL(*this, e);
687 switch (e->getStmtClass()) {
688 default:
689 getCIRGenModule().errorNYI(e->getSourceRange(),
690 std::string("l-value not implemented for '") +
691 e->getStmtClassName() + "'");
692 return LValue();
693 case Expr::ArraySubscriptExprClass:
694 return emitArraySubscriptExpr(e: cast<ArraySubscriptExpr>(Val: e));
695 case Expr::UnaryOperatorClass:
696 return emitUnaryOpLValue(e: cast<UnaryOperator>(Val: e));
697 case Expr::StringLiteralClass:
698 return emitStringLiteralLValue(e: cast<StringLiteral>(Val: e));
699 case Expr::MemberExprClass:
700 return emitMemberExpr(e: cast<MemberExpr>(Val: e));
701 case Expr::BinaryOperatorClass:
702 return emitBinaryOperatorLValue(e: cast<BinaryOperator>(Val: e));
703 case Expr::CompoundAssignOperatorClass: {
704 QualType ty = e->getType();
705 if (ty->getAs<AtomicType>()) {
706 cgm.errorNYI(e->getSourceRange(),
707 "CompoundAssignOperator with AtomicType");
708 return LValue();
709 }
710 if (!ty->isAnyComplexType())
711 return emitCompoundAssignmentLValue(e: cast<CompoundAssignOperator>(Val: e));
712 cgm.errorNYI(e->getSourceRange(),
713 "CompoundAssignOperator with ComplexType");
714 return LValue();
715 }
716 case Expr::CallExprClass:
717 case Expr::CXXMemberCallExprClass:
718 case Expr::CXXOperatorCallExprClass:
719 case Expr::UserDefinedLiteralClass:
720 return emitCallExprLValue(e: cast<CallExpr>(Val: e));
721 case Expr::ParenExprClass:
722 return emitLValue(e: cast<ParenExpr>(Val: e)->getSubExpr());
723 case Expr::DeclRefExprClass:
724 return emitDeclRefLValue(e: cast<DeclRefExpr>(Val: e));
725 case Expr::CStyleCastExprClass:
726 case Expr::CXXStaticCastExprClass:
727 case Expr::CXXDynamicCastExprClass:
728 case Expr::ImplicitCastExprClass:
729 return emitCastLValue(e: cast<CastExpr>(Val: e));
730 }
731}
732
733static std::string getVersionedTmpName(llvm::StringRef name, unsigned cnt) {
734 SmallString<256> buffer;
735 llvm::raw_svector_ostream out(buffer);
736 out << name << cnt;
737 return std::string(out.str());
738}
739
740std::string CIRGenFunction::getCounterAggTmpAsString() {
741 return getVersionedTmpName(name: "agg.tmp", cnt: counterAggTmp++);
742}
743
744void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,
745 QualType ty) {
746 // Ignore empty classes in C++.
747 if (getLangOpts().CPlusPlus) {
748 if (const RecordType *rt = ty->getAs<RecordType>()) {
749 if (cast<CXXRecordDecl>(Val: rt->getDecl())->isEmpty())
750 return;
751 }
752 }
753
754 // Cast the dest ptr to the appropriate i8 pointer type.
755 if (builder.isInt8Ty(destPtr.getElementType())) {
756 cgm.errorNYI(loc, "Cast the dest ptr to the appropriate i8 pointer type");
757 }
758
759 // Get size and alignment info for this aggregate.
760 const CharUnits size = getContext().getTypeSizeInChars(T: ty);
761 if (size.isZero()) {
762 // But note that getTypeInfo returns 0 for a VLA.
763 if (isa<VariableArrayType>(Val: getContext().getAsArrayType(T: ty))) {
764 cgm.errorNYI(loc,
765 "emitNullInitialization for zero size VariableArrayType");
766 } else {
767 return;
768 }
769 }
770
771 // If the type contains a pointer to data member we can't memset it to zero.
772 // Instead, create a null constant and copy it to the destination.
773 // TODO: there are other patterns besides zero that we can usefully memset,
774 // like -1, which happens to be the pattern used by member-pointers.
775 if (!cgm.getTypes().isZeroInitializable(ty)) {
776 cgm.errorNYI(loc, "type is not zero initializable");
777 }
778
779 // In LLVM Codegen: otherwise, just memset the whole thing to zero using
780 // Builder.CreateMemSet. In CIR just emit a store of #cir.zero to the
781 // respective address.
782 // Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);
783 const mlir::Value zeroValue = builder.getNullValue(convertType(ty), loc);
784 builder.createStore(loc, zeroValue, destPtr);
785}
786
787// TODO(cir): should be shared with LLVM codegen.
788bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) {
789 const Expr *e = ce->getSubExpr();
790
791 if (ce->getCastKind() == CK_UncheckedDerivedToBase)
792 return false;
793
794 if (isa<CXXThisExpr>(Val: e->IgnoreParens())) {
795 // We always assume that 'this' is never null.
796 return false;
797 }
798
799 if (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(Val: ce)) {
800 // And that glvalue casts are never null.
801 if (ice->isGLValue())
802 return false;
803 }
804
805 return true;
806}
807
808} // namespace clang::CIRGen
809

source code of clang/lib/CIR/CodeGen/CIRGenFunction.cpp