Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Internal per-function state used for AST-to-ClangIR code gen9//10//===----------------------------------------------------------------------===//1112#include "CIRGenFunction.h"1314#include "CIRGenCXXABI.h"15#include "CIRGenCall.h"16#include "CIRGenValue.h"17#include "mlir/IR/Location.h"18#include "clang/AST/ExprCXX.h"19#include "clang/AST/GlobalDecl.h"20#include "clang/CIR/MissingFeatures.h"2122#include <cassert>2324namespace clang::CIRGen {2526CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,27bool suppressNewContext)28: CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {}2930CIRGenFunction::~CIRGenFunction() {}3132// This is copied from clang/lib/CodeGen/CodeGenFunction.cpp33cir::TypeEvaluationKind CIRGenFunction::getEvaluationKind(QualType type) {34type = type.getCanonicalType();35while (true) {36switch (type->getTypeClass()) {37#define TYPE(name, parent)38#define ABSTRACT_TYPE(name, parent)39#define NON_CANONICAL_TYPE(name, parent) case Type::name:40#define DEPENDENT_TYPE(name, parent) case Type::name:41#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:42#include "clang/AST/TypeNodes.inc"43llvm_unreachable("non-canonical or dependent type in IR-generation");4445case Type::Auto:46case Type::DeducedTemplateSpecialization:47llvm_unreachable("undeduced type in IR-generation");4849// Various scalar types.50case Type::Builtin:51case Type::Pointer:52case Type::BlockPointer:53case Type::LValueReference:54case Type::RValueReference:55case Type::MemberPointer:56case Type::Vector:57case Type::ExtVector:58case Type::ConstantMatrix:59case Type::FunctionProto:60case Type::FunctionNoProto:61case Type::Enum:62case Type::ObjCObjectPointer:63case Type::Pipe:64case Type::BitInt:65case Type::HLSLAttributedResource:66case Type::HLSLInlineSpirv:67return cir::TEK_Scalar;6869// Complexes.70case Type::Complex:71return cir::TEK_Complex;7273// Arrays, records, and Objective-C objects.74case Type::ConstantArray:75case Type::IncompleteArray:76case Type::VariableArray:77case Type::Record:78case Type::ObjCObject:79case Type::ObjCInterface:80case Type::ArrayParameter:81return cir::TEK_Aggregate;8283// We operate on atomic values according to their underlying type.84case Type::Atomic:85type = cast<AtomicType>(type)->getValueType();86continue;87}88llvm_unreachable("unknown type kind!");89}90}9192mlir::Type CIRGenFunction::convertTypeForMem(QualType t) {93return cgm.getTypes().convertTypeForMem(t);94}9596mlir::Type CIRGenFunction::convertType(QualType t) {97return cgm.getTypes().convertType(t);98}99100mlir::Location CIRGenFunction::getLoc(SourceLocation srcLoc) {101// Some AST nodes might contain invalid source locations (e.g.102// CXXDefaultArgExpr), workaround that to still get something out.103if (srcLoc.isValid()) {104const SourceManager &sm = getContext().getSourceManager();105PresumedLoc pLoc = sm.getPresumedLoc(srcLoc);106StringRef filename = pLoc.getFilename();107return mlir::FileLineColLoc::get(builder.getStringAttr(filename),108pLoc.getLine(), pLoc.getColumn());109}110// Do our best...111assert(currSrcLoc && "expected to inherit some source location");112return *currSrcLoc;113}114115mlir::Location CIRGenFunction::getLoc(SourceRange srcLoc) {116// Some AST nodes might contain invalid source locations (e.g.117// CXXDefaultArgExpr), workaround that to still get something out.118if (srcLoc.isValid()) {119mlir::Location beg = getLoc(srcLoc.getBegin());120mlir::Location end = getLoc(srcLoc.getEnd());121SmallVector<mlir::Location, 2> locs = {beg, end};122mlir::Attribute metadata;123return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());124}125if (currSrcLoc) {126return *currSrcLoc;127}128// We're brave, but time to give up.129return builder.getUnknownLoc();130}131132mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, mlir::Location rhs) {133SmallVector<mlir::Location, 2> locs = {lhs, rhs};134mlir::Attribute metadata;135return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());136}137138bool CIRGenFunction::containsLabel(const Stmt *s, bool ignoreCaseStmts) {139// Null statement, not a label!140if (!s)141return false;142143// If this is a label, we have to emit the code, consider something like:144// if (0) { ... foo: bar(); } goto foo;145//146// TODO: If anyone cared, we could track __label__'s, since we know that you147// can't jump to one from outside their declared region.148if (isa<LabelStmt>(s))149return true;150151// If this is a case/default statement, and we haven't seen a switch, we152// have to emit the code.153if (isa<SwitchCase>(s) && !ignoreCaseStmts)154return true;155156// If this is a switch statement, we want to ignore case statements when we157// recursively process the sub-statements of the switch. If we haven't158// encountered a switch statement, we treat case statements like labels, but159// if we are processing a switch statement, case statements are expected.160if (isa<SwitchStmt>(s))161ignoreCaseStmts = true;162163// Scan subexpressions for verboten labels.164return std::any_of(s->child_begin(), s->child_end(),165[=](const Stmt *subStmt) {166return containsLabel(subStmt, ignoreCaseStmts);167});168}169170/// If the specified expression does not fold to a constant, or if it does but171/// contains a label, return false. If it constant folds return true and set172/// the boolean result in Result.173bool CIRGenFunction::constantFoldsToBool(const Expr *cond, bool &resultBool,174bool allowLabels) {175llvm::APSInt resultInt;176if (!constantFoldsToSimpleInteger(cond, resultInt, allowLabels))177return false;178179resultBool = resultInt.getBoolValue();180return true;181}182183/// If the specified expression does not fold to a constant, or if it does184/// fold but contains a label, return false. If it constant folds, return185/// true and set the folded value.186bool CIRGenFunction::constantFoldsToSimpleInteger(const Expr *cond,187llvm::APSInt &resultInt,188bool allowLabels) {189// FIXME: Rename and handle conversion of other evaluatable things190// to bool.191Expr::EvalResult result;192if (!cond->EvaluateAsInt(result, getContext()))193return false; // Not foldable, not integer or not fully evaluatable.194195llvm::APSInt intValue = result.Val.getInt();196if (!allowLabels && containsLabel(cond))197return false; // Contains a label.198199resultInt = intValue;200return true;201}202203void CIRGenFunction::emitAndUpdateRetAlloca(QualType type, mlir::Location loc,204CharUnits alignment) {205if (!type->isVoidType()) {206fnRetAlloca = emitAlloca("__retval", convertType(type), loc, alignment,207/*insertIntoFnEntryBlock=*/false);208}209}210211void CIRGenFunction::declare(mlir::Value addrVal, const Decl *var, QualType ty,212mlir::Location loc, CharUnits alignment,213bool isParam) {214const auto *namedVar = dyn_cast_or_null<NamedDecl>(var);215assert(namedVar && "Needs a named decl");216assert(!cir::MissingFeatures::cgfSymbolTable());217218auto allocaOp = cast<cir::AllocaOp>(addrVal.getDefiningOp());219if (isParam)220allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));221if (ty->isReferenceType() || ty.isConstQualified())222allocaOp.setConstantAttr(mlir::UnitAttr::get(&getMLIRContext()));223}224225void CIRGenFunction::LexicalScope::cleanup() {226CIRGenBuilderTy &builder = cgf.builder;227LexicalScope *localScope = cgf.curLexScope;228229if (returnBlock != nullptr) {230// Write out the return block, which loads the value from `__retval` and231// issues the `cir.return`.232mlir::OpBuilder::InsertionGuard guard(builder);233builder.setInsertionPointToEnd(returnBlock);234(void)emitReturn(*returnLoc);235}236237mlir::Block *curBlock = builder.getBlock();238if (isGlobalInit() && !curBlock)239return;240if (curBlock->mightHaveTerminator() && curBlock->getTerminator())241return;242243// Get rid of any empty block at the end of the scope.244bool entryBlock = builder.getInsertionBlock()->isEntryBlock();245if (!entryBlock && curBlock->empty()) {246curBlock->erase();247if (returnBlock != nullptr && returnBlock->getUses().empty())248returnBlock->erase();249return;250}251252// Reached the end of the scope.253{254mlir::OpBuilder::InsertionGuard guard(builder);255builder.setInsertionPointToEnd(curBlock);256257if (localScope->depth == 0) {258// Reached the end of the function.259if (returnBlock != nullptr) {260if (returnBlock->getUses().empty())261returnBlock->erase();262else {263builder.create<cir::BrOp>(*returnLoc, returnBlock);264return;265}266}267emitImplicitReturn();268return;269}270// Reached the end of a non-function scope. Some scopes, such as those271// used with the ?: operator, can return a value.272if (!localScope->isTernary() && !curBlock->mightHaveTerminator()) {273!retVal ? builder.create<cir::YieldOp>(localScope->endLoc)274: builder.create<cir::YieldOp>(localScope->endLoc, retVal);275}276}277}278279cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {280CIRGenBuilderTy &builder = cgf.getBuilder();281282if (!cgf.curFn.getFunctionType().hasVoidReturn()) {283// Load the value from `__retval` and return it via the `cir.return` op.284auto value = builder.create<cir::LoadOp>(285loc, cgf.curFn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);286return builder.create<cir::ReturnOp>(loc,287llvm::ArrayRef(value.getResult()));288}289return builder.create<cir::ReturnOp>(loc);290}291292// This is copied from CodeGenModule::MayDropFunctionReturn. This is a293// candidate for sharing between CIRGen and CodeGen.294static bool mayDropFunctionReturn(const ASTContext &astContext,295QualType returnType) {296// We can't just discard the return value for a record type with a complex297// destructor or a non-trivially copyable type.298if (const RecordType *recordType =299returnType.getCanonicalType()->getAs<RecordType>()) {300if (const auto *classDecl = dyn_cast<CXXRecordDecl>(recordType->getDecl()))301return classDecl->hasTrivialDestructor();302}303return returnType.isTriviallyCopyableType(astContext);304}305306void CIRGenFunction::LexicalScope::emitImplicitReturn() {307CIRGenBuilderTy &builder = cgf.getBuilder();308LexicalScope *localScope = cgf.curLexScope;309310const auto *fd = cast<clang::FunctionDecl>(cgf.curGD.getDecl());311312// In C++, flowing off the end of a non-void function is always undefined313// behavior. In C, flowing off the end of a non-void function is undefined314// behavior only if the non-existent return value is used by the caller.315// That influences whether the terminating op is trap, unreachable, or316// return.317if (cgf.getLangOpts().CPlusPlus && !fd->hasImplicitReturnZero() &&318!cgf.sawAsmBlock && !fd->getReturnType()->isVoidType() &&319builder.getInsertionBlock()) {320bool shouldEmitUnreachable =321cgf.cgm.getCodeGenOpts().StrictReturn ||322!mayDropFunctionReturn(fd->getASTContext(), fd->getReturnType());323324if (shouldEmitUnreachable) {325if (cgf.cgm.getCodeGenOpts().OptimizationLevel == 0)326builder.create<cir::TrapOp>(localScope->endLoc);327else328builder.create<cir::UnreachableOp>(localScope->endLoc);329builder.clearInsertionPoint();330return;331}332}333334(void)emitReturn(localScope->endLoc);335}336337void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,338cir::FuncOp fn, cir::FuncType funcType,339FunctionArgList args, SourceLocation loc,340SourceLocation startLoc) {341assert(!curFn &&342"CIRGenFunction can only be used for one function at a time");343344curFn = fn;345346const Decl *d = gd.getDecl();347const auto *fd = dyn_cast_or_null<FunctionDecl>(d);348curFuncDecl = d->getNonClosureContext();349350mlir::Block *entryBB = &fn.getBlocks().front();351builder.setInsertionPointToStart(entryBB);352353// TODO(cir): this should live in `emitFunctionProlog354// Declare all the function arguments in the symbol table.355for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {356const VarDecl *paramVar = std::get<0>(nameValue);357mlir::Value paramVal = std::get<1>(nameValue);358CharUnits alignment = getContext().getDeclAlign(paramVar);359mlir::Location paramLoc = getLoc(paramVar->getSourceRange());360paramVal.setLoc(paramLoc);361362mlir::Value addrVal =363emitAlloca(cast<NamedDecl>(paramVar)->getName(),364convertType(paramVar->getType()), paramLoc, alignment,365/*insertIntoFnEntryBlock=*/true);366367declare(addrVal, paramVar, paramVar->getType(), paramLoc, alignment,368/*isParam=*/true);369370setAddrOfLocalVar(paramVar, Address(addrVal, alignment));371372bool isPromoted = isa<ParmVarDecl>(paramVar) &&373cast<ParmVarDecl>(paramVar)->isKNRPromoted();374assert(!cir::MissingFeatures::constructABIArgDirectExtend());375if (isPromoted)376cgm.errorNYI(fd->getSourceRange(), "Function argument demotion");377378// Location of the store to the param storage tracked as beginning of379// the function body.380mlir::Location fnBodyBegin = getLoc(fd->getBody()->getBeginLoc());381builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);382}383assert(builder.getInsertionBlock() && "Should be valid");384385// When the current function is not void, create an address to store the386// result value.387if (!returnType->isVoidType())388emitAndUpdateRetAlloca(returnType, getLoc(fd->getBody()->getEndLoc()),389getContext().getTypeAlignInChars(returnType));390391if (isa_and_nonnull<CXXMethodDecl>(d) &&392cast<CXXMethodDecl>(d)->isInstance()) {393cgm.getCXXABI().emitInstanceFunctionProlog(loc, *this);394395const auto *md = cast<CXXMethodDecl>(d);396if (md->getParent()->isLambda() && md->getOverloadedOperator() == OO_Call) {397cgm.errorNYI(loc, "lambda call operator");398} else {399// Not in a lambda; just use 'this' from the method.400// FIXME: Should we generate a new load for each use of 'this'? The fast401// register allocator would be happier...402cxxThisValue = cxxabiThisValue;403}404405assert(!cir::MissingFeatures::sanitizers());406assert(!cir::MissingFeatures::emitTypeCheck());407}408}409410void CIRGenFunction::finishFunction(SourceLocation endLoc) {}411412mlir::LogicalResult CIRGenFunction::emitFunctionBody(const clang::Stmt *body) {413auto result = mlir::LogicalResult::success();414if (const CompoundStmt *block = dyn_cast<CompoundStmt>(body))415emitCompoundStmtWithoutScope(*block);416else417result = emitStmt(body, /*useCurrentScope=*/true);418419return result;420}421422static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {423// Remove any leftover blocks that are unreachable and empty, since they do424// not represent unreachable code useful for warnings nor anything deemed425// useful in general.426SmallVector<mlir::Block *> blocksToDelete;427for (mlir::Block &block : func.getBlocks()) {428if (block.empty() && block.getUses().empty())429blocksToDelete.push_back(&block);430}431for (mlir::Block *block : blocksToDelete)432block->erase();433}434435cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,436cir::FuncType funcType) {437const auto funcDecl = cast<FunctionDecl>(gd.getDecl());438curGD = gd;439440SourceLocation loc = funcDecl->getLocation();441Stmt *body = funcDecl->getBody();442SourceRange bodyRange =443body ? body->getSourceRange() : funcDecl->getLocation();444445SourceLocRAIIObject fnLoc{*this, loc.isValid() ? getLoc(loc)446: builder.getUnknownLoc()};447448auto validMLIRLoc = [&](clang::SourceLocation clangLoc) {449return clangLoc.isValid() ? getLoc(clangLoc) : builder.getUnknownLoc();450};451const mlir::Location fusedLoc = mlir::FusedLoc::get(452&getMLIRContext(),453{validMLIRLoc(bodyRange.getBegin()), validMLIRLoc(bodyRange.getEnd())});454mlir::Block *entryBB = fn.addEntryBlock();455456FunctionArgList args;457QualType retTy = buildFunctionArgList(gd, args);458459{460LexicalScope lexScope(*this, fusedLoc, entryBB);461462startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());463464if (isa<CXXDestructorDecl>(funcDecl)) {465emitDestructorBody(args);466} else if (isa<CXXConstructorDecl>(funcDecl)) {467emitConstructorBody(args);468} else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice &&469funcDecl->hasAttr<CUDAGlobalAttr>()) {470getCIRGenModule().errorNYI(bodyRange, "CUDA kernel");471} else if (isa<CXXMethodDecl>(funcDecl) &&472cast<CXXMethodDecl>(funcDecl)->isLambdaStaticInvoker()) {473getCIRGenModule().errorNYI(bodyRange, "Lambda static invoker");474} else if (funcDecl->isDefaulted() && isa<CXXMethodDecl>(funcDecl) &&475(cast<CXXMethodDecl>(funcDecl)->isCopyAssignmentOperator() ||476cast<CXXMethodDecl>(funcDecl)->isMoveAssignmentOperator())) {477// Implicit copy-assignment gets the same special treatment as implicit478// copy-constructors.479emitImplicitAssignmentOperatorBody(args);480} else if (body) {481if (mlir::failed(emitFunctionBody(body))) {482fn.erase();483return nullptr;484}485} else {486// Anything without a body should have been handled above.487llvm_unreachable("no definition for normal function");488}489490if (mlir::failed(fn.verifyBody()))491return nullptr;492493finishFunction(bodyRange.getEnd());494}495496eraseEmptyAndUnusedBlocks(fn);497return fn;498}499500void CIRGenFunction::emitConstructorBody(FunctionArgList &args) {501assert(!cir::MissingFeatures::sanitizers());502const auto *ctor = cast<CXXConstructorDecl>(curGD.getDecl());503CXXCtorType ctorType = curGD.getCtorType();504505assert((cgm.getTarget().getCXXABI().hasConstructorVariants() ||506ctorType == Ctor_Complete) &&507"can only generate complete ctor for this ABI");508509if (ctorType == Ctor_Complete && isConstructorDelegationValid(ctor) &&510cgm.getTarget().getCXXABI().hasConstructorVariants()) {511emitDelegateCXXConstructorCall(ctor, Ctor_Base, args, ctor->getEndLoc());512return;513}514515const FunctionDecl *definition = nullptr;516Stmt *body = ctor->getBody(definition);517assert(definition == ctor && "emitting wrong constructor body");518519if (isa_and_nonnull<CXXTryStmt>(body)) {520cgm.errorNYI(ctor->getSourceRange(), "emitConstructorBody: try body");521return;522}523524assert(!cir::MissingFeatures::incrementProfileCounter());525assert(!cir::MissingFeatures::runCleanupsScope());526527// TODO: in restricted cases, we can emit the vbase initializers of a528// complete ctor and then delegate to the base ctor.529530// Emit the constructor prologue, i.e. the base and member initializers.531emitCtorPrologue(ctor, ctorType, args);532533// TODO(cir): propagate this result via mlir::logical result. Just unreachable534// now just to have it handled.535if (mlir::failed(emitStmt(body, true))) {536cgm.errorNYI(ctor->getSourceRange(),537"emitConstructorBody: emit body statement failed.");538return;539}540}541542/// Emits the body of the current destructor.543void CIRGenFunction::emitDestructorBody(FunctionArgList &args) {544const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(curGD.getDecl());545CXXDtorType dtorType = curGD.getDtorType();546547// For an abstract class, non-base destructors are never used (and can't548// be emitted in general, because vbase dtors may not have been validated549// by Sema), but the Itanium ABI doesn't make them optional and Clang may550// in fact emit references to them from other compilations, so emit them551// as functions containing a trap instruction.552if (dtorType != Dtor_Base && dtor->getParent()->isAbstract()) {553cgm.errorNYI(dtor->getSourceRange(), "abstract base class destructors");554return;555}556557Stmt *body = dtor->getBody();558assert(body && !cir::MissingFeatures::incrementProfileCounter());559560// The call to operator delete in a deleting destructor happens561// outside of the function-try-block, which means it's always562// possible to delegate the destructor body to the complete563// destructor. Do so.564if (dtorType == Dtor_Deleting) {565cgm.errorNYI(dtor->getSourceRange(), "deleting destructor");566return;567}568569// If the body is a function-try-block, enter the try before570// anything else.571const bool isTryBody = isa_and_nonnull<CXXTryStmt>(body);572if (isTryBody)573cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");574575assert(!cir::MissingFeatures::sanitizers());576assert(!cir::MissingFeatures::dtorCleanups());577578// If this is the complete variant, just invoke the base variant;579// the epilogue will destruct the virtual bases. But we can't do580// this optimization if the body is a function-try-block, because581// we'd introduce *two* handler blocks. In the Microsoft ABI, we582// always delegate because we might not have a definition in this TU.583switch (dtorType) {584case Dtor_Comdat:585llvm_unreachable("not expecting a COMDAT");586case Dtor_Deleting:587llvm_unreachable("already handled deleting case");588589case Dtor_Complete:590assert((body || getTarget().getCXXABI().isMicrosoft()) &&591"can't emit a dtor without a body for non-Microsoft ABIs");592593assert(!cir::MissingFeatures::dtorCleanups());594595// TODO(cir): A complete destructor is supposed to call the base destructor.596// Since we have to emit both dtor kinds we just fall through for now and.597// As long as we don't support virtual bases this should be functionally598// equivalent.599assert(!cir::MissingFeatures::completeDtors());600601// Fallthrough: act like we're in the base variant.602[[fallthrough]];603604case Dtor_Base:605assert(body);606607assert(!cir::MissingFeatures::dtorCleanups());608assert(!cir::MissingFeatures::vtableInitialization());609610if (isTryBody) {611cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");612} else if (body) {613(void)emitStmt(body, /*useCurrentScope=*/true);614} else {615assert(dtor->isImplicit() && "bodyless dtor not implicit");616// nothing to do besides what's in the epilogue617}618// -fapple-kext must inline any call to this dtor into619// the caller's body.620assert(!cir::MissingFeatures::appleKext());621622break;623}624625assert(!cir::MissingFeatures::dtorCleanups());626627// Exit the try if applicable.628if (isTryBody)629cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");630}631632/// Given a value of type T* that may not be to a complete object, construct633/// an l-vlaue withi the natural pointee alignment of T.634LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val,635QualType ty) {636// FIXME(cir): is it safe to assume Op->getResult(0) is valid? Perhaps637// assert on the result type first.638LValueBaseInfo baseInfo;639assert(!cir::MissingFeatures::opTBAA());640CharUnits align = cgm.getNaturalTypeAlignment(ty, &baseInfo);641return makeAddrLValue(Address(val, align), ty, baseInfo);642}643644LValue CIRGenFunction::makeNaturalAlignAddrLValue(mlir::Value val,645QualType ty) {646LValueBaseInfo baseInfo;647CharUnits alignment = cgm.getNaturalTypeAlignment(ty, &baseInfo);648Address addr(val, convertTypeForMem(ty), alignment);649assert(!cir::MissingFeatures::opTBAA());650return makeAddrLValue(addr, ty, baseInfo);651}652653clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,654FunctionArgList &args) {655const auto *fd = cast<FunctionDecl>(gd.getDecl());656QualType retTy = fd->getReturnType();657658const auto *md = dyn_cast<CXXMethodDecl>(fd);659if (md && md->isInstance()) {660if (cgm.getCXXABI().hasThisReturn(gd))661cgm.errorNYI(fd->getSourceRange(), "this return");662else if (cgm.getCXXABI().hasMostDerivedReturn(gd))663cgm.errorNYI(fd->getSourceRange(), "most derived return");664cgm.getCXXABI().buildThisParam(*this, args);665}666667if (const auto *cd = dyn_cast<CXXConstructorDecl>(fd))668if (cd->getInheritedConstructor())669cgm.errorNYI(fd->getSourceRange(),670"buildFunctionArgList: inherited constructor");671672for (auto *param : fd->parameters())673args.push_back(param);674675if (md && (isa<CXXConstructorDecl>(md) || isa<CXXDestructorDecl>(md)))676assert(!cir::MissingFeatures::cxxabiStructorImplicitParam());677678return retTy;679}680681/// Emit code to compute a designator that specifies the location682/// of the expression.683/// FIXME: document this function better.684LValue CIRGenFunction::emitLValue(const Expr *e) {685// FIXME: ApplyDebugLocation DL(*this, e);686switch (e->getStmtClass()) {687default:688getCIRGenModule().errorNYI(e->getSourceRange(),689std::string("l-value not implemented for '") +690e->getStmtClassName() + "'");691return LValue();692case Expr::ArraySubscriptExprClass:693return emitArraySubscriptExpr(cast<ArraySubscriptExpr>(e));694case Expr::UnaryOperatorClass:695return emitUnaryOpLValue(cast<UnaryOperator>(e));696case Expr::StringLiteralClass:697return emitStringLiteralLValue(cast<StringLiteral>(e));698case Expr::MemberExprClass:699return emitMemberExpr(cast<MemberExpr>(e));700case Expr::BinaryOperatorClass:701return emitBinaryOperatorLValue(cast<BinaryOperator>(e));702case Expr::CompoundAssignOperatorClass: {703QualType ty = e->getType();704if (ty->getAs<AtomicType>()) {705cgm.errorNYI(e->getSourceRange(),706"CompoundAssignOperator with AtomicType");707return LValue();708}709if (!ty->isAnyComplexType())710return emitCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));711cgm.errorNYI(e->getSourceRange(),712"CompoundAssignOperator with ComplexType");713return LValue();714}715case Expr::CallExprClass:716case Expr::CXXMemberCallExprClass:717case Expr::CXXOperatorCallExprClass:718case Expr::UserDefinedLiteralClass:719return emitCallExprLValue(cast<CallExpr>(e));720case Expr::ParenExprClass:721return emitLValue(cast<ParenExpr>(e)->getSubExpr());722case Expr::DeclRefExprClass:723return emitDeclRefLValue(cast<DeclRefExpr>(e));724case Expr::CStyleCastExprClass:725case Expr::CXXStaticCastExprClass:726case Expr::CXXDynamicCastExprClass:727case Expr::ImplicitCastExprClass:728return emitCastLValue(cast<CastExpr>(e));729}730}731732static std::string getVersionedTmpName(llvm::StringRef name, unsigned cnt) {733SmallString<256> buffer;734llvm::raw_svector_ostream out(buffer);735out << name << cnt;736return std::string(out.str());737}738739std::string CIRGenFunction::getCounterAggTmpAsString() {740return getVersionedTmpName("agg.tmp", counterAggTmp++);741}742743void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,744QualType ty) {745// Ignore empty classes in C++.746if (getLangOpts().CPlusPlus) {747if (const RecordType *rt = ty->getAs<RecordType>()) {748if (cast<CXXRecordDecl>(rt->getDecl())->isEmpty())749return;750}751}752753// Cast the dest ptr to the appropriate i8 pointer type.754if (builder.isInt8Ty(destPtr.getElementType())) {755cgm.errorNYI(loc, "Cast the dest ptr to the appropriate i8 pointer type");756}757758// Get size and alignment info for this aggregate.759const CharUnits size = getContext().getTypeSizeInChars(ty);760if (size.isZero()) {761// But note that getTypeInfo returns 0 for a VLA.762if (isa<VariableArrayType>(getContext().getAsArrayType(ty))) {763cgm.errorNYI(loc,764"emitNullInitialization for zero size VariableArrayType");765} else {766return;767}768}769770// If the type contains a pointer to data member we can't memset it to zero.771// Instead, create a null constant and copy it to the destination.772// TODO: there are other patterns besides zero that we can usefully memset,773// like -1, which happens to be the pattern used by member-pointers.774if (!cgm.getTypes().isZeroInitializable(ty)) {775cgm.errorNYI(loc, "type is not zero initializable");776}777778// In LLVM Codegen: otherwise, just memset the whole thing to zero using779// Builder.CreateMemSet. In CIR just emit a store of #cir.zero to the780// respective address.781// Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, false);782const mlir::Value zeroValue = builder.getNullValue(convertType(ty), loc);783builder.createStore(loc, zeroValue, destPtr);784}785786// TODO(cir): should be shared with LLVM codegen.787bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) {788const Expr *e = ce->getSubExpr();789790if (ce->getCastKind() == CK_UncheckedDerivedToBase)791return false;792793if (isa<CXXThisExpr>(e->IgnoreParens())) {794// We always assume that 'this' is never null.795return false;796}797798if (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(ce)) {799// And that glvalue casts are never null.800if (ice->isGLValue())801return false;802}803804return true;805}806807} // namespace clang::CIRGen808809810