Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
213799 views
//===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===//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// This contains code dealing with code generation of C++ expressions9//10//===----------------------------------------------------------------------===//1112#include "CIRGenCXXABI.h"13#include "CIRGenFunction.h"1415#include "clang/AST/DeclCXX.h"16#include "clang/AST/ExprCXX.h"17#include "clang/CIR/MissingFeatures.h"1819using namespace clang;20using namespace clang::CIRGen;2122namespace {23struct MemberCallInfo {24RequiredArgs reqArgs;25// Number of prefix arguments for the call. Ignores the `this` pointer.26unsigned prefixSize;27};28} // namespace2930static MemberCallInfo commonBuildCXXMemberOrOperatorCall(31CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr,32mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce,33CallArgList &args, CallArgList *rtlArgs) {34assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) ||35isa<CXXOperatorCallExpr>(ce));36assert(md->isInstance() &&37"Trying to emit a member or operator call expr on a static method!");3839// Push the this ptr.40const CXXRecordDecl *rd =41cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md);42args.add(RValue::get(thisPtr), cgf.getTypes().deriveThisType(rd, md));4344// If there is an implicit parameter (e.g. VTT), emit it.45if (implicitParam) {46args.add(RValue::get(implicitParam), implicitParamTy);47}4849const auto *fpt = md->getType()->castAs<FunctionProtoType>();50RequiredArgs required =51RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size());52unsigned prefixSize = args.size() - 1;5354// Add the rest of the call args55if (rtlArgs) {56// Special case: if the caller emitted the arguments right-to-left already57// (prior to emitting the *this argument), we're done. This happens for58// assignment operators.59args.addFrom(*rtlArgs);60} else if (ce) {61// Special case: skip first argument of CXXOperatorCall (it is "this").62unsigned argsToSkip = isa<CXXOperatorCallExpr>(ce) ? 1 : 0;63cgf.emitCallArgs(args, fpt, drop_begin(ce->arguments(), argsToSkip),64ce->getDirectCallee());65} else {66assert(67fpt->getNumParams() == 0 &&68"No CallExpr specified for function with non-zero number of arguments");69}7071// return {required, prefixSize};72return {required, prefixSize};73}7475RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(76const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue,77bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow,78const Expr *base) {79assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce));8081if (md->isVirtual()) {82cgm.errorNYI(ce->getSourceRange(),83"emitCXXMemberOrOperatorMemberCallExpr: virtual call");84return RValue::get(nullptr);85}8687// Note on trivial assignment88// --------------------------89// Classic codegen avoids generating the trivial copy/move assignment operator90// when it isn't necessary, choosing instead to just produce IR with an91// equivalent effect. We have chosen not to do that in CIR, instead emitting92// trivial copy/move assignment operators and allowing later transformations93// to optimize them away if appropriate.9495// C++17 demands that we evaluate the RHS of a (possibly-compound) assignment96// operator before the LHS.97CallArgList rtlArgStorage;98CallArgList *rtlArgs = nullptr;99if (auto *oce = dyn_cast<CXXOperatorCallExpr>(ce)) {100if (oce->isAssignmentOp()) {101rtlArgs = &rtlArgStorage;102emitCallArgs(*rtlArgs, md->getType()->castAs<FunctionProtoType>(),103drop_begin(ce->arguments(), 1), ce->getDirectCallee(),104/*ParamsToSkip*/ 0);105}106}107108LValue thisPtr;109if (isArrow) {110LValueBaseInfo baseInfo;111assert(!cir::MissingFeatures::opTBAA());112Address thisValue = emitPointerWithAlignment(base, &baseInfo);113thisPtr = makeAddrLValue(thisValue, base->getType(), baseInfo);114} else {115thisPtr = emitLValue(base);116}117118if (isa<CXXConstructorDecl>(md)) {119cgm.errorNYI(ce->getSourceRange(),120"emitCXXMemberOrOperatorMemberCallExpr: constructor call");121return RValue::get(nullptr);122}123124if ((md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion())) &&125isa<CXXDestructorDecl>(md))126return RValue::get(nullptr);127128// Compute the function type we're calling129const CXXMethodDecl *calleeDecl = md;130const CIRGenFunctionInfo *fInfo = nullptr;131if (isa<CXXDestructorDecl>(calleeDecl)) {132cgm.errorNYI(ce->getSourceRange(),133"emitCXXMemberOrOperatorMemberCallExpr: destructor call");134return RValue::get(nullptr);135}136137fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl);138139mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);140141assert(!cir::MissingFeatures::sanitizers());142assert(!cir::MissingFeatures::emitTypeCheck());143144if (isa<CXXDestructorDecl>(calleeDecl)) {145cgm.errorNYI(ce->getSourceRange(),146"emitCXXMemberOrOperatorMemberCallExpr: destructor call");147return RValue::get(nullptr);148}149150assert(!cir::MissingFeatures::sanitizers());151if (getLangOpts().AppleKext) {152cgm.errorNYI(ce->getSourceRange(),153"emitCXXMemberOrOperatorMemberCallExpr: AppleKext");154return RValue::get(nullptr);155}156CIRGenCallee callee =157CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));158159return emitCXXMemberOrOperatorCall(160calleeDecl, callee, returnValue, thisPtr.getPointer(),161/*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);162}163164RValue165CIRGenFunction::emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,166const CXXMethodDecl *md,167ReturnValueSlot returnValue) {168assert(md->isInstance() &&169"Trying to emit a member call expr on a static method!");170return emitCXXMemberOrOperatorMemberCallExpr(171e, md, returnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr,172/*IsArrow=*/false, e->getArg(0));173}174175RValue CIRGenFunction::emitCXXMemberOrOperatorCall(176const CXXMethodDecl *md, const CIRGenCallee &callee,177ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,178QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {179const auto *fpt = md->getType()->castAs<FunctionProtoType>();180CallArgList args;181MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(182*this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);183auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(184args, fpt, callInfo.reqArgs, callInfo.prefixSize);185assert((ce || currSrcLoc) && "expected source location");186mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;187assert(!cir::MissingFeatures::opCallMustTail());188return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);189}190191static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,192unsigned minElements,193mlir::Value &numElements,194mlir::Value &sizeWithoutCookie) {195QualType type = e->getAllocatedType();196mlir::Location loc = cgf.getLoc(e->getSourceRange());197198if (!e->isArray()) {199CharUnits typeSize = cgf.getContext().getTypeSizeInChars(type);200sizeWithoutCookie = cgf.getBuilder().getConstant(201loc, cir::IntAttr::get(cgf.SizeTy, typeSize.getQuantity()));202return sizeWithoutCookie;203}204205cgf.cgm.errorNYI(e->getSourceRange(), "emitCXXNewAllocSize: array");206return {};207}208209static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,210QualType allocType, Address newPtr,211AggValueSlot::Overlap_t mayOverlap) {212// FIXME: Refactor with emitExprAsInit.213switch (cgf.getEvaluationKind(allocType)) {214case cir::TEK_Scalar:215cgf.emitScalarInit(init, cgf.getLoc(init->getSourceRange()),216cgf.makeAddrLValue(newPtr, allocType), false);217return;218case cir::TEK_Complex:219cgf.cgm.errorNYI(init->getSourceRange(),220"storeAnyExprIntoOneUnit: complex");221return;222case cir::TEK_Aggregate: {223assert(!cir::MissingFeatures::aggValueSlotGC());224assert(!cir::MissingFeatures::sanitizers());225AggValueSlot slot = AggValueSlot::forAddr(226newPtr, allocType.getQualifiers(), AggValueSlot::IsDestructed,227AggValueSlot::IsNotAliased, mayOverlap, AggValueSlot::IsNotZeroed);228cgf.emitAggExpr(init, slot);229return;230}231}232llvm_unreachable("bad evaluation kind");233}234235static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,236QualType elementType, mlir::Type elementTy,237Address newPtr, mlir::Value numElements,238mlir::Value allocSizeWithoutCookie) {239assert(!cir::MissingFeatures::generateDebugInfo());240if (e->isArray()) {241cgf.cgm.errorNYI(e->getSourceRange(), "emitNewInitializer: array");242} else if (const Expr *init = e->getInitializer()) {243storeAnyExprIntoOneUnit(cgf, init, e->getAllocatedType(), newPtr,244AggValueSlot::DoesNotOverlap);245}246}247248/// Emit a call to an operator new or operator delete function, as implicitly249/// created by new-expressions and delete-expressions.250static RValue emitNewDeleteCall(CIRGenFunction &cgf,251const FunctionDecl *calleeDecl,252const FunctionProtoType *calleeType,253const CallArgList &args) {254cir::CIRCallOpInterface callOrTryCall;255cir::FuncOp calleePtr = cgf.cgm.getAddrOfFunction(calleeDecl);256CIRGenCallee callee =257CIRGenCallee::forDirect(calleePtr, GlobalDecl(calleeDecl));258RValue rv =259cgf.emitCall(cgf.cgm.getTypes().arrangeFreeFunctionCall(args, calleeType),260callee, ReturnValueSlot(), args, &callOrTryCall);261262/// C++1y [expr.new]p10:263/// [In a new-expression,] an implementation is allowed to omit a call264/// to a replaceable global allocation function.265///266/// We model such elidable calls with the 'builtin' attribute.267assert(!cir::MissingFeatures::attributeBuiltin());268return rv;269}270271mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {272// The element type being allocated.273QualType allocType = getContext().getBaseElementType(e->getAllocatedType());274275// 1. Build a call to the allocation function.276FunctionDecl *allocator = e->getOperatorNew();277278// If there is a brace-initializer, cannot allocate fewer elements than inits.279unsigned minElements = 0;280if (e->isArray() && e->hasInitializer()) {281cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array initializer");282}283284mlir::Value numElements = nullptr;285mlir::Value allocSizeWithoutCookie = nullptr;286mlir::Value allocSize = emitCXXNewAllocSize(287*this, e, minElements, numElements, allocSizeWithoutCookie);288CharUnits allocAlign = getContext().getTypeAlignInChars(allocType);289290// Emit the allocation call.291Address allocation = Address::invalid();292CallArgList allocatorArgs;293if (allocator->isReservedGlobalPlacementOperator()) {294cgm.errorNYI(e->getSourceRange(),295"emitCXXNewExpr: reserved global placement operator");296} else {297const FunctionProtoType *allocatorType =298allocator->getType()->castAs<FunctionProtoType>();299unsigned paramsToSkip = 0;300301// The allocation size is the first argument.302QualType sizeType = getContext().getSizeType();303allocatorArgs.add(RValue::get(allocSize), sizeType);304++paramsToSkip;305306if (allocSize != allocSizeWithoutCookie) {307CharUnits cookieAlign = getSizeAlign(); // FIXME: Ask the ABI.308allocAlign = std::max(allocAlign, cookieAlign);309}310311// The allocation alignment may be passed as the second argument.312if (e->passAlignment()) {313cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: pass alignment");314}315316// FIXME: Why do we not pass a CalleeDecl here?317emitCallArgs(allocatorArgs, allocatorType, e->placement_arguments(),318AbstractCallee(), paramsToSkip);319RValue rv =320emitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);321322// Set !heapallocsite metadata on the call to operator new.323assert(!cir::MissingFeatures::generateDebugInfo());324325// If this was a call to a global replaceable allocation function that does326// not take an alignment argument, the allocator is known to produce storage327// that's suitably aligned for any object that fits, up to a known328// threshold. Otherwise assume it's suitably aligned for the allocated type.329CharUnits allocationAlign = allocAlign;330if (!e->passAlignment() &&331allocator->isReplaceableGlobalAllocationFunction()) {332const TargetInfo &target = cgm.getASTContext().getTargetInfo();333unsigned allocatorAlign = llvm::bit_floor(std::min<uint64_t>(334target.getNewAlign(), getContext().getTypeSize(allocType)));335allocationAlign = std::max(336allocationAlign, getContext().toCharUnitsFromBits(allocatorAlign));337}338339mlir::Value allocPtr = rv.getValue();340allocation = Address(341allocPtr, mlir::cast<cir::PointerType>(allocPtr.getType()).getPointee(),342allocationAlign);343}344345// Emit a null check on the allocation result if the allocation346// function is allowed to return null (because it has a non-throwing347// exception spec or is the reserved placement new) and we have an348// interesting initializer will be running sanitizers on the initialization.349bool nullCheck = e->shouldNullCheckAllocation() &&350(!allocType.isPODType(getContext()) || e->hasInitializer());351assert(!cir::MissingFeatures::exprNewNullCheck());352if (nullCheck)353cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: null check");354355// If there's an operator delete, enter a cleanup to call it if an356// exception is thrown.357if (e->getOperatorDelete() &&358!e->getOperatorDelete()->isReservedGlobalPlacementOperator())359cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");360361if (allocSize != allocSizeWithoutCookie)362cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");363364mlir::Type elementTy = convertTypeForMem(allocType);365Address result = builder.createElementBitCast(getLoc(e->getSourceRange()),366allocation, elementTy);367368// Passing pointer through launder.invariant.group to avoid propagation of369// vptrs information which may be included in previous type.370// To not break LTO with different optimizations levels, we do it regardless371// of optimization level.372if (cgm.getCodeGenOpts().StrictVTablePointers &&373allocator->isReservedGlobalPlacementOperator())374cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: strict vtable pointers");375376assert(!cir::MissingFeatures::sanitizers());377378emitNewInitializer(*this, e, allocType, elementTy, result, numElements,379allocSizeWithoutCookie);380return result.getPointer();381}382383384