Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenCall.cpp
213799 views
//===--- CIRGenCall.cpp - Encapsulate calling convention details ----------===//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// These classes wrap the information about a call or function definition used9// to handle ABI compliancy.10//11//===----------------------------------------------------------------------===//1213#include "CIRGenCall.h"14#include "CIRGenCXXABI.h"15#include "CIRGenFunction.h"16#include "CIRGenFunctionInfo.h"17#include "clang/CIR/MissingFeatures.h"1819using namespace clang;20using namespace clang::CIRGen;2122CIRGenFunctionInfo *23CIRGenFunctionInfo::create(CanQualType resultType,24llvm::ArrayRef<CanQualType> argTypes,25RequiredArgs required) {26// The first slot allocated for arg type slot is for the return value.27void *buffer = operator new(28totalSizeToAlloc<CanQualType>(argTypes.size() + 1));2930assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());3132CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();3334fi->required = required;35fi->numArgs = argTypes.size();3637fi->getArgTypes()[0] = resultType;38std::copy(argTypes.begin(), argTypes.end(), fi->argTypesBegin());39assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());4041return fi;42}4344cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {45mlir::Type resultType = convertType(fi.getReturnType());46SmallVector<mlir::Type, 8> argTypes;47argTypes.reserve(fi.getNumRequiredArgs());4849for (const CanQualType &argType : fi.requiredArguments())50argTypes.push_back(convertType(argType));5152return cir::FuncType::get(argTypes,53(resultType ? resultType : builder.getVoidTy()),54fi.isVariadic());55}5657CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {58assert(!cir::MissingFeatures::opCallVirtual());59return *this;60}6162void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {63// In classic codegen:64// Function to store a first-class aggregate into memory. We prefer to65// store the elements rather than the aggregate to be more friendly to66// fast-isel.67// In CIR codegen:68// Emit the most simple cir.store possible (e.g. a store for a whole69// record), which can later be broken down in other CIR levels (or prior70// to dialect codegen).7172// Stored result for the callers of this function expected to be in the same73// scope as the value, don't make assumptions about current insertion point.74mlir::OpBuilder::InsertionGuard guard(builder);75builder.setInsertionPointAfter(value.getDefiningOp());76builder.createStore(*currSrcLoc, value, dest);77}7879static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder,80mlir::NamedAttrList &attrs,81const FunctionProtoType *fpt) {82if (!fpt)83return;8485if (!isUnresolvedExceptionSpec(fpt->getExceptionSpecType()) &&86fpt->isNothrow())87attrs.set(cir::CIRDialect::getNoThrowAttrName(),88mlir::UnitAttr::get(builder.getContext()));89}9091/// Construct the CIR attribute list of a function or call.92void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,93mlir::NamedAttrList &attrs) {94assert(!cir::MissingFeatures::opCallCallConv());95auto sideEffect = cir::SideEffect::All;9697addAttributesFromFunctionProtoType(getBuilder(), attrs,98calleeInfo.getCalleeFunctionProtoType());99100const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();101102if (targetDecl) {103if (targetDecl->hasAttr<NoThrowAttr>())104attrs.set(cir::CIRDialect::getNoThrowAttrName(),105mlir::UnitAttr::get(&getMLIRContext()));106107if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {108addAttributesFromFunctionProtoType(109getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());110assert(!cir::MissingFeatures::opCallAttrs());111}112113assert(!cir::MissingFeatures::opCallAttrs());114115// 'const', 'pure' and 'noalias' attributed functions are also nounwind.116if (targetDecl->hasAttr<ConstAttr>()) {117// gcc specifies that 'const' functions have greater restrictions than118// 'pure' functions, so they also cannot have infinite loops.119sideEffect = cir::SideEffect::Const;120} else if (targetDecl->hasAttr<PureAttr>()) {121// gcc specifies that 'pure' functions cannot have infinite loops.122sideEffect = cir::SideEffect::Pure;123}124125assert(!cir::MissingFeatures::opCallAttrs());126}127128assert(!cir::MissingFeatures::opCallAttrs());129130attrs.set(cir::CIRDialect::getSideEffectAttrName(),131cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));132}133134/// Returns the canonical formal type of the given C++ method.135static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {136return md->getType()137->getCanonicalTypeUnqualified()138.getAs<FunctionProtoType>();139}140141/// Adds the formal parameters in FPT to the given prefix. If any parameter in142/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.143/// TODO(cir): this should be shared with LLVM codegen144static void appendParameterTypes(const CIRGenTypes &cgt,145SmallVectorImpl<CanQualType> &prefix,146CanQual<FunctionProtoType> fpt) {147assert(!cir::MissingFeatures::opCallExtParameterInfo());148// Fast path: don't touch param info if we don't need to.149if (!fpt->hasExtParameterInfos()) {150prefix.append(fpt->param_type_begin(), fpt->param_type_end());151return;152}153154cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");155}156157const CIRGenFunctionInfo &158CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) {159auto *md = cast<CXXMethodDecl>(gd.getDecl());160161llvm::SmallVector<CanQualType, 16> argTypes;162argTypes.push_back(deriveThisType(md->getParent(), md));163164bool passParams = true;165166if (auto *cd = dyn_cast<CXXConstructorDecl>(md)) {167// A base class inheriting constructor doesn't get forwarded arguments168// needed to construct a virtual base (or base class thereof)169if (cd->getInheritedConstructor())170cgm.errorNYI(cd->getSourceRange(),171"arrangeCXXStructorDeclaration: inheriting constructor");172}173174CanQual<FunctionProtoType> fpt = getFormalType(md);175176if (passParams)177appendParameterTypes(*this, argTypes, fpt);178179assert(!cir::MissingFeatures::implicitConstructorArgs());180181RequiredArgs required =182(passParams && md->isVariadic() ? RequiredArgs(argTypes.size())183: RequiredArgs::All);184185CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front()186: theCXXABI.hasMostDerivedReturn(gd)187? astContext.VoidPtrTy188: astContext.VoidTy;189190assert(!theCXXABI.hasThisReturn(gd) &&191"Please send PR with a test and remove this");192193assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());194assert(!cir::MissingFeatures::opCallFnInfoOpts());195196return arrangeCIRFunctionInfo(resultType, argTypes, required);197}198199/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR200/// qualification. Either or both of `rd` and `md` may be null. A null `rd`201/// indicates that there is no meaningful 'this' type, and a null `md` can occur202/// when calling a method pointer.203CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd,204const CXXMethodDecl *md) {205QualType recTy;206if (rd) {207recTy = getASTContext().getTagDeclType(rd)->getCanonicalTypeInternal();208} else {209// This can happen with the MS ABI. It shouldn't need anything more than210// setting recTy to VoidTy here, but we're flagging it for now because we211// don't have the full handling implemented.212cgm.errorNYI("deriveThisType: no record decl");213recTy = getASTContext().VoidTy;214}215216if (md)217recTy = getASTContext().getAddrSpaceQualType(218recTy, md->getMethodQualifiers().getAddressSpace());219return getASTContext().getPointerType(CanQualType::CreateUnsafe(recTy));220}221222/// Arrange the CIR function layout for a value of the given function type, on223/// top of any implicit parameters already stored.224static const CIRGenFunctionInfo &225arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,226CanQual<FunctionProtoType> fpt) {227assert(!cir::MissingFeatures::opCallFnInfoOpts());228RequiredArgs required =229RequiredArgs::getFromProtoWithExtraSlots(fpt, prefix.size());230assert(!cir::MissingFeatures::opCallExtParameterInfo());231appendParameterTypes(cgt, prefix, fpt);232CanQualType resultType = fpt->getReturnType().getUnqualifiedType();233return cgt.arrangeCIRFunctionInfo(resultType, prefix, required);234}235236void CIRGenFunction::emitDelegateCallArg(CallArgList &args,237const VarDecl *param,238SourceLocation loc) {239// StartFunction converted the ABI-lowered parameter(s) into a local alloca.240// We need to turn that into an r-value suitable for emitCall241Address local = getAddrOfLocalVar(param);242243QualType type = param->getType();244245if (type->getAsCXXRecordDecl()) {246cgm.errorNYI(param->getSourceRange(),247"emitDelegateCallArg: record argument");248return;249}250251// GetAddrOfLocalVar returns a pointer-to-pointer for references, but the252// argument needs to be the original pointer.253if (type->isReferenceType()) {254args.add(255RValue::get(builder.createLoad(getLoc(param->getSourceRange()), local)),256type);257} else if (getLangOpts().ObjCAutoRefCount) {258cgm.errorNYI(param->getSourceRange(),259"emitDelegateCallArg: ObjCAutoRefCount");260// For the most part, we just need to load the alloca, except that aggregate261// r-values are actually pointers to temporaries.262} else {263args.add(convertTempToRValue(local, type, loc), type);264}265266// Deactivate the cleanup for the callee-destructed param that was pushed.267assert(!cir::MissingFeatures::thunks());268if (type->isRecordType() &&269type->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&270param->needsDestruction(getContext())) {271cgm.errorNYI(param->getSourceRange(),272"emitDelegateCallArg: callee-destructed param");273}274}275276static const CIRGenFunctionInfo &277arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,278const CallArgList &args,279const FunctionType *fnType) {280281RequiredArgs required = RequiredArgs::All;282283if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {284if (proto->isVariadic())285required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);286if (proto->hasExtParameterInfos())287cgm.errorNYI("call to functions with extra parameter info");288} else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(289cast<FunctionNoProtoType>(fnType)))290cgm.errorNYI("call to function without a prototype");291292SmallVector<CanQualType, 16> argTypes;293for (const CallArg &arg : args)294argTypes.push_back(cgt.getASTContext().getCanonicalParamType(arg.ty));295296CanQualType retType = fnType->getReturnType()297->getCanonicalTypeUnqualified()298.getUnqualifiedType();299300assert(!cir::MissingFeatures::opCallFnInfoOpts());301return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);302}303304/// Arrange a call to a C++ method, passing the given arguments.305///306/// passProtoArgs indicates whether `args` has args for the parameters in the307/// given CXXConstructorDecl.308const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall(309const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind,310bool passProtoArgs) {311312// FIXME: Kill copy.313llvm::SmallVector<CanQualType, 16> argTypes;314for (const auto &arg : args)315argTypes.push_back(astContext.getCanonicalParamType(arg.ty));316317assert(!cir::MissingFeatures::implicitConstructorArgs());318// +1 for implicit this, which should always be args[0]319unsigned totalPrefixArgs = 1;320321CanQual<FunctionProtoType> fpt = getFormalType(d);322RequiredArgs required =323passProtoArgs324? RequiredArgs::getFromProtoWithExtraSlots(fpt, totalPrefixArgs)325: RequiredArgs::All;326327GlobalDecl gd(d, ctorKind);328if (theCXXABI.hasThisReturn(gd))329cgm.errorNYI(d->getSourceRange(),330"arrangeCXXConstructorCall: hasThisReturn");331if (theCXXABI.hasMostDerivedReturn(gd))332cgm.errorNYI(d->getSourceRange(),333"arrangeCXXConstructorCall: hasMostDerivedReturn");334CanQualType resultType = astContext.VoidTy;335336assert(!cir::MissingFeatures::opCallFnInfoOpts());337assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());338339return arrangeCIRFunctionInfo(resultType, argTypes, required);340}341342/// Arrange a call to a C++ method, passing the given arguments.343///344/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It345/// does not count `this`.346const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(347const CallArgList &args, const FunctionProtoType *proto,348RequiredArgs required, unsigned numPrefixArgs) {349assert(!cir::MissingFeatures::opCallExtParameterInfo());350assert(numPrefixArgs + 1 <= args.size() &&351"Emitting a call with less args than the required prefix?");352353// FIXME: Kill copy.354llvm::SmallVector<CanQualType, 16> argTypes;355for (const CallArg &arg : args)356argTypes.push_back(astContext.getCanonicalParamType(arg.ty));357358assert(!cir::MissingFeatures::opCallFnInfoOpts());359return arrangeCIRFunctionInfo(proto->getReturnType()360->getCanonicalTypeUnqualified()361.getUnqualifiedType(),362argTypes, required);363}364365const CIRGenFunctionInfo &366CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,367const FunctionType *fnType) {368return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);369}370371/// Arrange the argument and result information for a declaration or definition372/// of the given C++ non-static member function. The member function must be an373/// ordinary function, i.e. not a constructor or destructor.374const CIRGenFunctionInfo &375CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) {376assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");377assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");378379auto prototype =380md->getType()->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();381assert(!cir::MissingFeatures::cudaSupport());382383if (md->isInstance()) {384// The abstract case is perfectly fine.385auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);386return arrangeCXXMethodType(thisType, prototype.getTypePtr(), md);387}388389return arrangeFreeFunctionType(prototype);390}391392/// Arrange the argument and result information for a call to an unknown C++393/// non-static member function of the given abstract type. (A null RD means we394/// don't have any meaningful "this" argument type, so fall back to a generic395/// pointer type). The member fucntion must be an ordinary function, i.e. not a396/// constructor or destructor.397const CIRGenFunctionInfo &398CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd,399const FunctionProtoType *fpt,400const CXXMethodDecl *md) {401llvm::SmallVector<CanQualType, 16> argTypes;402403// Add the 'this' pointer.404argTypes.push_back(deriveThisType(rd, md));405406assert(!cir::MissingFeatures::opCallFnInfoOpts());407return ::arrangeCIRFunctionInfo(408*this, argTypes,409fpt->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());410}411412/// Arrange the argument and result information for the declaration or413/// definition of the given function.414const CIRGenFunctionInfo &415CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {416if (const auto *md = dyn_cast<CXXMethodDecl>(fd))417if (md->isInstance())418return arrangeCXXMethodDeclaration(md);419420CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();421422assert(isa<FunctionType>(funcTy));423// TODO: setCUDAKernelCallingConvention424assert(!cir::MissingFeatures::cudaSupport());425426// When declaring a function without a prototype, always use a non-variadic427// type.428if (CanQual<FunctionNoProtoType> noProto =429funcTy.getAs<FunctionNoProtoType>()) {430assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());431assert(!cir::MissingFeatures::opCallFnInfoOpts());432return arrangeCIRFunctionInfo(noProto->getReturnType(), {},433RequiredArgs::All);434}435436return arrangeFreeFunctionType(funcTy.castAs<FunctionProtoType>());437}438439static cir::CIRCallOpInterface440emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,441cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,442cir::FuncOp directFuncOp,443const SmallVectorImpl<mlir::Value> &cirCallArgs,444const mlir::NamedAttrList &attrs) {445CIRGenBuilderTy &builder = cgf.getBuilder();446447assert(!cir::MissingFeatures::opCallSurroundingTry());448assert(!cir::MissingFeatures::invokeOp());449450assert(builder.getInsertionBlock() && "expected valid basic block");451452cir::CallOp op;453if (indirectFuncTy) {454// TODO(cir): Set calling convention for indirect calls.455assert(!cir::MissingFeatures::opCallCallConv());456op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,457cirCallArgs, attrs);458} else {459op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs);460}461462return op;463}464465const CIRGenFunctionInfo &466CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {467SmallVector<CanQualType, 16> argTypes;468assert(!cir::MissingFeatures::opCallFnInfoOpts());469return ::arrangeCIRFunctionInfo(*this, argTypes, fpt);470}471472const CIRGenFunctionInfo &473CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {474CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();475assert(!cir::MissingFeatures::opCallFnInfoOpts());476return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));477}478479RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,480const CIRGenCallee &callee,481ReturnValueSlot returnValue,482const CallArgList &args,483cir::CIRCallOpInterface *callOp,484mlir::Location loc) {485QualType retTy = funcInfo.getReturnType();486cir::FuncType cirFuncTy = getTypes().getFunctionType(funcInfo);487488SmallVector<mlir::Value, 16> cirCallArgs(args.size());489490assert(!cir::MissingFeatures::emitLifetimeMarkers());491492// Translate all of the arguments as necessary to match the CIR lowering.493for (auto [argNo, arg, canQualArgType] :494llvm::enumerate(args, funcInfo.argTypes())) {495496// Insert a padding argument to ensure proper alignment.497assert(!cir::MissingFeatures::opCallPaddingArgs());498499mlir::Type argType = convertType(canQualArgType);500if (!mlir::isa<cir::RecordType>(argType)) {501mlir::Value v;502if (arg.isAggregate())503cgm.errorNYI(loc, "emitCall: aggregate call argument");504v = arg.getKnownRValue().getValue();505506// We might have to widen integers, but we should never truncate.507if (argType != v.getType() && mlir::isa<cir::IntType>(v.getType()))508cgm.errorNYI(loc, "emitCall: widening integer call argument");509510// If the argument doesn't match, perform a bitcast to coerce it. This511// can happen due to trivial type mismatches.512// TODO(cir): When getFunctionType is added, assert that this isn't513// needed.514assert(!cir::MissingFeatures::opCallBitcastArg());515cirCallArgs[argNo] = v;516} else {517Address src = Address::invalid();518if (!arg.isAggregate())519cgm.errorNYI(loc, "emitCall: non-aggregate call argument");520else521src = arg.hasLValue() ? arg.getKnownLValue().getAddress()522: arg.getKnownRValue().getAggregateAddress();523524// Fast-isel and the optimizer generally like scalar values better than525// FCAs, so we flatten them if this is safe to do for this argument.526auto argRecordTy = cast<cir::RecordType>(argType);527mlir::Type srcTy = src.getElementType();528// FIXME(cir): get proper location for each argument.529mlir::Location argLoc = loc;530531// If the source type is smaller than the destination type of the532// coerce-to logic, copy the source value into a temp alloca the size533// of the destination type to allow loading all of it. The bits past534// the source value are left undef.535// FIXME(cir): add data layout info and compare sizes instead of536// matching the types.537//538// uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);539// uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);540// if (SrcSize < DstSize) {541assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());542if (srcTy != argRecordTy) {543cgm.errorNYI(loc, "emitCall: source type does not match argument type");544} else {545// FIXME(cir): this currently only runs when the types are exactly the546// same, but should be when alloc sizes are the same, fix this as soon547// as datalayout gets introduced.548assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());549}550551// assert(NumCIRArgs == STy.getMembers().size());552// In LLVMGen: Still only pass the struct without any gaps but mark it553// as such somehow.554//555// In CIRGen: Emit a load from the "whole" struct,556// which shall be broken later by some lowering step into multiple557// loads.558assert(!cir::MissingFeatures::lowerAggregateLoadStore());559cirCallArgs[argNo] = builder.createLoad(argLoc, src);560}561}562563const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);564mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();565566assert(!cir::MissingFeatures::opCallInAlloca());567568mlir::NamedAttrList attrs;569StringRef funcName;570if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))571funcName = calleeFuncOp.getName();572573assert(!cir::MissingFeatures::opCallCallConv());574assert(!cir::MissingFeatures::opCallAttrs());575cgm.constructAttributeList(callee.getAbstractInfo(), attrs);576577assert(!cir::MissingFeatures::invokeOp());578579cir::FuncType indirectFuncTy;580mlir::Value indirectFuncVal;581cir::FuncOp directFuncOp;582if (auto fnOp = dyn_cast<cir::FuncOp>(calleePtr)) {583directFuncOp = fnOp;584} else {585[[maybe_unused]] mlir::ValueTypeRange<mlir::ResultRange> resultTypes =586calleePtr->getResultTypes();587[[maybe_unused]] auto funcPtrTy =588mlir::dyn_cast<cir::PointerType>(resultTypes.front());589assert(funcPtrTy && mlir::isa<cir::FuncType>(funcPtrTy.getPointee()) &&590"expected pointer to function");591592indirectFuncTy = cirFuncTy;593indirectFuncVal = calleePtr->getResult(0);594}595596mlir::Location callLoc = loc;597cir::CIRCallOpInterface theCall =598emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,599cirCallArgs, attrs);600601if (callOp)602*callOp = theCall;603604assert(!cir::MissingFeatures::opCallMustTail());605assert(!cir::MissingFeatures::opCallReturn());606607mlir::Type retCIRTy = convertType(retTy);608if (isa<cir::VoidType>(retCIRTy))609return getUndefRValue(retTy);610switch (getEvaluationKind(retTy)) {611case cir::TEK_Aggregate: {612Address destPtr = returnValue.getValue();613614if (!destPtr.isValid())615destPtr = createMemTemp(retTy, callLoc, getCounterAggTmpAsString());616617mlir::ResultRange results = theCall->getOpResults();618assert(results.size() <= 1 && "multiple returns from a call");619620SourceLocRAIIObject loc{*this, callLoc};621emitAggregateStore(results[0], destPtr);622return RValue::getAggregate(destPtr);623}624case cir::TEK_Scalar: {625mlir::ResultRange results = theCall->getOpResults();626assert(results.size() == 1 && "unexpected number of returns");627628// If the argument doesn't match, perform a bitcast to coerce it. This629// can happen due to trivial type mismatches.630if (results[0].getType() != retCIRTy)631cgm.errorNYI(loc, "bitcast on function return value");632633mlir::Region *region = builder.getBlock()->getParent();634if (region != theCall->getParentRegion())635cgm.errorNYI(loc, "function calls with cleanup");636637return RValue::get(results[0]);638}639case cir::TEK_Complex:640cgm.errorNYI(loc, "unsupported evaluation kind of function call result");641return getUndefRValue(retTy);642}643llvm_unreachable("Invalid evaluation kind");644}645646void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,647clang::QualType argType) {648assert(argType->isReferenceType() == e->isGLValue() &&649"reference binding to unmaterialized r-value!");650651if (e->isGLValue()) {652assert(e->getObjectKind() == OK_Ordinary);653return args.add(emitReferenceBindingToExpr(e), argType);654}655656bool hasAggregateEvalKind = hasAggregateEvaluationKind(argType);657658// In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.659// However, we still have to push an EH-only cleanup in case we unwind before660// we make it to the call.661if (argType->isRecordType() &&662argType->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {663assert(!cir::MissingFeatures::msabi());664cgm.errorNYI(e->getSourceRange(), "emitCallArg: msabi is NYI");665}666667if (hasAggregateEvalKind && isa<ImplicitCastExpr>(e) &&668cast<CastExpr>(e)->getCastKind() == CK_LValueToRValue) {669LValue lv = emitLValue(cast<CastExpr>(e)->getSubExpr());670assert(lv.isSimple());671args.addUncopiedAggregate(lv, argType);672return;673}674675args.add(emitAnyExprToTemp(e), argType);676}677678QualType CIRGenFunction::getVarArgType(const Expr *arg) {679// System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC680// implicitly widens null pointer constants that are arguments to varargs681// functions to pointer-sized ints.682if (!getTarget().getTriple().isOSWindows())683return arg->getType();684685assert(!cir::MissingFeatures::msabi());686cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");687return arg->getType();688}689690/// Similar to emitAnyExpr(), however, the result will always be accessible691/// even if no aggregate location is provided.692RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) {693AggValueSlot aggSlot = AggValueSlot::ignored();694695if (hasAggregateEvaluationKind(e->getType()))696aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()),697getCounterAggTmpAsString());698699return emitAnyExpr(e, aggSlot);700}701702void CIRGenFunction::emitCallArgs(703CallArgList &args, PrototypeWrapper prototype,704llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,705AbstractCallee callee, unsigned paramsToSkip) {706llvm::SmallVector<QualType, 16> argTypes;707708assert(!cir::MissingFeatures::opCallCallConv());709710// First, if a prototype was provided, use those argument types.711bool isVariadic = false;712if (prototype.p) {713assert(!cir::MissingFeatures::opCallObjCMethod());714715const auto *fpt = cast<const FunctionProtoType *>(prototype.p);716isVariadic = fpt->isVariadic();717assert(!cir::MissingFeatures::opCallCallConv());718argTypes.assign(fpt->param_type_begin() + paramsToSkip,719fpt->param_type_end());720}721722// If we still have any arguments, emit them using the type of the argument.723for (const clang::Expr *a : llvm::drop_begin(argRange, argTypes.size()))724argTypes.push_back(isVariadic ? getVarArgType(a) : a->getType());725assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));726727// We must evaluate arguments from right to left in the MS C++ ABI, because728// arguments are destroyed left to right in the callee. As a special case,729// there are certain language constructs taht require left-to-right730// evaluation, and in those cases we consider the evaluation order requirement731// to trump the "destruction order is reverse construction order" guarantee.732auto leftToRight = true;733assert(!cir::MissingFeatures::msabi());734735auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,736RValue emittedArg) {737if (!callee.hasFunctionDecl() || i >= callee.getNumParams())738return;739auto *ps = callee.getParamDecl(i)->getAttr<PassObjectSizeAttr>();740if (!ps)741return;742743assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());744cgm.errorNYI("emit implicit object size for call arg");745};746747// Evaluate each argument in the appropriate order.748size_t callArgsStart = args.size();749for (size_t i = 0; i != argTypes.size(); ++i) {750size_t idx = leftToRight ? i : argTypes.size() - i - 1;751CallExpr::const_arg_iterator currentArg = argRange.begin() + idx;752size_t initialArgSize = args.size();753754emitCallArg(args, *currentArg, argTypes[idx]);755756// In particular, we depend on it being the last arg in Args, and the757// objectsize bits depend on there only being one arg if !LeftToRight.758assert(initialArgSize + 1 == args.size() &&759"The code below depends on only adding one arg per emitCallArg");760(void)initialArgSize;761762// Since pointer argument are never emitted as LValue, it is safe to emit763// non-null argument check for r-value only.764if (!args.back().hasLValue()) {765RValue rvArg = args.back().getKnownRValue();766assert(!cir::MissingFeatures::sanitizers());767maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);768}769770if (!leftToRight)771std::reverse(args.begin() + callArgsStart, args.end());772}773}774775776