1//===--- CIRGenCall.cpp - Encapsulate calling convention details ----------===//
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// These classes wrap the information about a call or function definition used
10// to handle ABI compliancy.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CIRGenCall.h"
15#include "CIRGenCXXABI.h"
16#include "CIRGenFunction.h"
17#include "CIRGenFunctionInfo.h"
18#include "clang/CIR/MissingFeatures.h"
19
20using namespace clang;
21using namespace clang::CIRGen;
22
23CIRGenFunctionInfo *
24CIRGenFunctionInfo::create(CanQualType resultType,
25 llvm::ArrayRef<CanQualType> argTypes,
26 RequiredArgs required) {
27 // The first slot allocated for arg type slot is for the return value.
28 void *buffer = operator new(
29 totalSizeToAlloc<CanQualType>(Counts: argTypes.size() + 1));
30
31 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
32
33 CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();
34
35 fi->required = required;
36 fi->numArgs = argTypes.size();
37
38 fi->getArgTypes()[0] = resultType;
39 std::copy(first: argTypes.begin(), last: argTypes.end(), result: fi->argTypesBegin());
40 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
41
42 return fi;
43}
44
45cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
46 mlir::Type resultType = convertType(fi.getReturnType());
47 SmallVector<mlir::Type, 8> argTypes;
48 argTypes.reserve(fi.getNumRequiredArgs());
49
50 for (const CanQualType &argType : fi.requiredArguments())
51 argTypes.push_back(convertType(argType));
52
53 return cir::FuncType::get(argTypes,
54 (resultType ? resultType : builder.getVoidTy()),
55 fi.isVariadic());
56}
57
58CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
59 assert(!cir::MissingFeatures::opCallVirtual());
60 return *this;
61}
62
63void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {
64 // In classic codegen:
65 // Function to store a first-class aggregate into memory. We prefer to
66 // store the elements rather than the aggregate to be more friendly to
67 // fast-isel.
68 // In CIR codegen:
69 // Emit the most simple cir.store possible (e.g. a store for a whole
70 // record), which can later be broken down in other CIR levels (or prior
71 // to dialect codegen).
72
73 // Stored result for the callers of this function expected to be in the same
74 // scope as the value, don't make assumptions about current insertion point.
75 mlir::OpBuilder::InsertionGuard guard(builder);
76 builder.setInsertionPointAfter(value.getDefiningOp());
77 builder.createStore(*currSrcLoc, value, dest);
78}
79
80static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder,
81 mlir::NamedAttrList &attrs,
82 const FunctionProtoType *fpt) {
83 if (!fpt)
84 return;
85
86 if (!isUnresolvedExceptionSpec(fpt->getExceptionSpecType()) &&
87 fpt->isNothrow())
88 attrs.set(cir::CIRDialect::getNoThrowAttrName(),
89 mlir::UnitAttr::get(builder.getContext()));
90}
91
92/// Construct the CIR attribute list of a function or call.
93void CIRGenModule::constructAttributeList(CIRGenCalleeInfo calleeInfo,
94 mlir::NamedAttrList &attrs) {
95 assert(!cir::MissingFeatures::opCallCallConv());
96 auto sideEffect = cir::SideEffect::All;
97
98 addAttributesFromFunctionProtoType(getBuilder(), attrs,
99 calleeInfo.getCalleeFunctionProtoType());
100
101 const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
102
103 if (targetDecl) {
104 if (targetDecl->hasAttr<NoThrowAttr>())
105 attrs.set(cir::CIRDialect::getNoThrowAttrName(),
106 mlir::UnitAttr::get(&getMLIRContext()));
107
108 if (const FunctionDecl *func = dyn_cast<FunctionDecl>(Val: targetDecl)) {
109 addAttributesFromFunctionProtoType(
110 getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
111 assert(!cir::MissingFeatures::opCallAttrs());
112 }
113
114 assert(!cir::MissingFeatures::opCallAttrs());
115
116 // 'const', 'pure' and 'noalias' attributed functions are also nounwind.
117 if (targetDecl->hasAttr<ConstAttr>()) {
118 // gcc specifies that 'const' functions have greater restrictions than
119 // 'pure' functions, so they also cannot have infinite loops.
120 sideEffect = cir::SideEffect::Const;
121 } else if (targetDecl->hasAttr<PureAttr>()) {
122 // gcc specifies that 'pure' functions cannot have infinite loops.
123 sideEffect = cir::SideEffect::Pure;
124 }
125
126 assert(!cir::MissingFeatures::opCallAttrs());
127 }
128
129 assert(!cir::MissingFeatures::opCallAttrs());
130
131 attrs.set(cir::CIRDialect::getSideEffectAttrName(),
132 cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
133}
134
135/// Returns the canonical formal type of the given C++ method.
136static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {
137 return md->getType()
138 ->getCanonicalTypeUnqualified()
139 .getAs<FunctionProtoType>();
140}
141
142/// Adds the formal parameters in FPT to the given prefix. If any parameter in
143/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
144/// TODO(cir): this should be shared with LLVM codegen
145static void appendParameterTypes(const CIRGenTypes &cgt,
146 SmallVectorImpl<CanQualType> &prefix,
147 CanQual<FunctionProtoType> fpt) {
148 assert(!cir::MissingFeatures::opCallExtParameterInfo());
149 // Fast path: don't touch param info if we don't need to.
150 if (!fpt->hasExtParameterInfos()) {
151 prefix.append(in_start: fpt->param_type_begin(), in_end: fpt->param_type_end());
152 return;
153 }
154
155 cgt.getCGModule().errorNYI(feature: "appendParameterTypes: hasExtParameterInfos");
156}
157
158const CIRGenFunctionInfo &
159CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) {
160 auto *md = cast<CXXMethodDecl>(Val: gd.getDecl());
161
162 llvm::SmallVector<CanQualType, 16> argTypes;
163 argTypes.push_back(Elt: deriveThisType(rd: md->getParent(), md));
164
165 bool passParams = true;
166
167 if (auto *cd = dyn_cast<CXXConstructorDecl>(Val: md)) {
168 // A base class inheriting constructor doesn't get forwarded arguments
169 // needed to construct a virtual base (or base class thereof)
170 if (cd->getInheritedConstructor())
171 cgm.errorNYI(cd->getSourceRange(),
172 "arrangeCXXStructorDeclaration: inheriting constructor");
173 }
174
175 CanQual<FunctionProtoType> fpt = getFormalType(md);
176
177 if (passParams)
178 appendParameterTypes(cgt: *this, prefix&: argTypes, fpt);
179
180 assert(!cir::MissingFeatures::implicitConstructorArgs());
181
182 RequiredArgs required =
183 (passParams && md->isVariadic() ? RequiredArgs(argTypes.size())
184 : RequiredArgs::All);
185
186 CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front()
187 : theCXXABI.hasMostDerivedReturn(gd)
188 ? astContext.VoidPtrTy
189 : astContext.VoidTy;
190
191 assert(!theCXXABI.hasThisReturn(gd) &&
192 "Please send PR with a test and remove this");
193
194 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
195 assert(!cir::MissingFeatures::opCallFnInfoOpts());
196
197 return arrangeCIRFunctionInfo(returnType: resultType, argTypes, required);
198}
199
200/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
201/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
202/// indicates that there is no meaningful 'this' type, and a null `md` can occur
203/// when calling a method pointer.
204CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd,
205 const CXXMethodDecl *md) {
206 QualType recTy;
207 if (rd) {
208 recTy = getASTContext().getTagDeclType(Decl: rd)->getCanonicalTypeInternal();
209 } else {
210 // This can happen with the MS ABI. It shouldn't need anything more than
211 // setting recTy to VoidTy here, but we're flagging it for now because we
212 // don't have the full handling implemented.
213 cgm.errorNYI(feature: "deriveThisType: no record decl");
214 recTy = getASTContext().VoidTy;
215 }
216
217 if (md)
218 recTy = getASTContext().getAddrSpaceQualType(
219 T: recTy, AddressSpace: md->getMethodQualifiers().getAddressSpace());
220 return getASTContext().getPointerType(T: CanQualType::CreateUnsafe(Other: recTy));
221}
222
223/// Arrange the CIR function layout for a value of the given function type, on
224/// top of any implicit parameters already stored.
225static const CIRGenFunctionInfo &
226arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,
227 CanQual<FunctionProtoType> fpt) {
228 assert(!cir::MissingFeatures::opCallFnInfoOpts());
229 RequiredArgs required =
230 RequiredArgs::getFromProtoWithExtraSlots(prototype: fpt, additional: prefix.size());
231 assert(!cir::MissingFeatures::opCallExtParameterInfo());
232 appendParameterTypes(cgt, prefix, fpt);
233 CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
234 return cgt.arrangeCIRFunctionInfo(returnType: resultType, argTypes: prefix, required);
235}
236
237void CIRGenFunction::emitDelegateCallArg(CallArgList &args,
238 const VarDecl *param,
239 SourceLocation loc) {
240 // StartFunction converted the ABI-lowered parameter(s) into a local alloca.
241 // We need to turn that into an r-value suitable for emitCall
242 Address local = getAddrOfLocalVar(vd: param);
243
244 QualType type = param->getType();
245
246 if (type->getAsCXXRecordDecl()) {
247 cgm.errorNYI(param->getSourceRange(),
248 "emitDelegateCallArg: record argument");
249 return;
250 }
251
252 // GetAddrOfLocalVar returns a pointer-to-pointer for references, but the
253 // argument needs to be the original pointer.
254 if (type->isReferenceType()) {
255 args.add(
256 RValue::get(builder.createLoad(getLoc(param->getSourceRange()), local)),
257 type);
258 } else if (getLangOpts().ObjCAutoRefCount) {
259 cgm.errorNYI(param->getSourceRange(),
260 "emitDelegateCallArg: ObjCAutoRefCount");
261 // For the most part, we just need to load the alloca, except that aggregate
262 // r-values are actually pointers to temporaries.
263 } else {
264 args.add(rvalue: convertTempToRValue(addr: local, type, loc), type);
265 }
266
267 // Deactivate the cleanup for the callee-destructed param that was pushed.
268 assert(!cir::MissingFeatures::thunks());
269 if (type->isRecordType() &&
270 type->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&
271 param->needsDestruction(Ctx: getContext())) {
272 cgm.errorNYI(param->getSourceRange(),
273 "emitDelegateCallArg: callee-destructed param");
274 }
275}
276
277static const CIRGenFunctionInfo &
278arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
279 const CallArgList &args,
280 const FunctionType *fnType) {
281
282 RequiredArgs required = RequiredArgs::All;
283
284 if (const auto *proto = dyn_cast<FunctionProtoType>(Val: fnType)) {
285 if (proto->isVariadic())
286 required = RequiredArgs::getFromProtoWithExtraSlots(prototype: proto, additional: 0);
287 if (proto->hasExtParameterInfos())
288 cgm.errorNYI(feature: "call to functions with extra parameter info");
289 } else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
290 fnType: cast<FunctionNoProtoType>(Val: fnType)))
291 cgm.errorNYI(feature: "call to function without a prototype");
292
293 SmallVector<CanQualType, 16> argTypes;
294 for (const CallArg &arg : args)
295 argTypes.push_back(Elt: cgt.getASTContext().getCanonicalParamType(T: arg.ty));
296
297 CanQualType retType = fnType->getReturnType()
298 ->getCanonicalTypeUnqualified()
299 .getUnqualifiedType();
300
301 assert(!cir::MissingFeatures::opCallFnInfoOpts());
302 return cgt.arrangeCIRFunctionInfo(returnType: retType, argTypes, required);
303}
304
305/// Arrange a call to a C++ method, passing the given arguments.
306///
307/// passProtoArgs indicates whether `args` has args for the parameters in the
308/// given CXXConstructorDecl.
309const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall(
310 const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind,
311 bool passProtoArgs) {
312
313 // FIXME: Kill copy.
314 llvm::SmallVector<CanQualType, 16> argTypes;
315 for (const auto &arg : args)
316 argTypes.push_back(Elt: astContext.getCanonicalParamType(T: arg.ty));
317
318 assert(!cir::MissingFeatures::implicitConstructorArgs());
319 // +1 for implicit this, which should always be args[0]
320 unsigned totalPrefixArgs = 1;
321
322 CanQual<FunctionProtoType> fpt = getFormalType(md: d);
323 RequiredArgs required =
324 passProtoArgs
325 ? RequiredArgs::getFromProtoWithExtraSlots(prototype: fpt, additional: totalPrefixArgs)
326 : RequiredArgs::All;
327
328 GlobalDecl gd(d, ctorKind);
329 if (theCXXABI.hasThisReturn(gd))
330 cgm.errorNYI(d->getSourceRange(),
331 "arrangeCXXConstructorCall: hasThisReturn");
332 if (theCXXABI.hasMostDerivedReturn(gd))
333 cgm.errorNYI(d->getSourceRange(),
334 "arrangeCXXConstructorCall: hasMostDerivedReturn");
335 CanQualType resultType = astContext.VoidTy;
336
337 assert(!cir::MissingFeatures::opCallFnInfoOpts());
338 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
339
340 return arrangeCIRFunctionInfo(returnType: resultType, argTypes, required);
341}
342
343/// Arrange a call to a C++ method, passing the given arguments.
344///
345/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
346/// does not count `this`.
347const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(
348 const CallArgList &args, const FunctionProtoType *proto,
349 RequiredArgs required, unsigned numPrefixArgs) {
350 assert(!cir::MissingFeatures::opCallExtParameterInfo());
351 assert(numPrefixArgs + 1 <= args.size() &&
352 "Emitting a call with less args than the required prefix?");
353
354 // FIXME: Kill copy.
355 llvm::SmallVector<CanQualType, 16> argTypes;
356 for (const CallArg &arg : args)
357 argTypes.push_back(Elt: astContext.getCanonicalParamType(T: arg.ty));
358
359 assert(!cir::MissingFeatures::opCallFnInfoOpts());
360 return arrangeCIRFunctionInfo(returnType: proto->getReturnType()
361 ->getCanonicalTypeUnqualified()
362 .getUnqualifiedType(),
363 argTypes, required);
364}
365
366const CIRGenFunctionInfo &
367CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
368 const FunctionType *fnType) {
369 return arrangeFreeFunctionLikeCall(cgt&: *this, cgm, args, fnType);
370}
371
372/// Arrange the argument and result information for a declaration or definition
373/// of the given C++ non-static member function. The member function must be an
374/// ordinary function, i.e. not a constructor or destructor.
375const CIRGenFunctionInfo &
376CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) {
377 assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
378 assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
379
380 auto prototype =
381 md->getType()->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
382 assert(!cir::MissingFeatures::cudaSupport());
383
384 if (md->isInstance()) {
385 // The abstract case is perfectly fine.
386 auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
387 return arrangeCXXMethodType(rd: thisType, ftp: prototype.getTypePtr(), md);
388 }
389
390 return arrangeFreeFunctionType(fpt: prototype);
391}
392
393/// Arrange the argument and result information for a call to an unknown C++
394/// non-static member function of the given abstract type. (A null RD means we
395/// don't have any meaningful "this" argument type, so fall back to a generic
396/// pointer type). The member fucntion must be an ordinary function, i.e. not a
397/// constructor or destructor.
398const CIRGenFunctionInfo &
399CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd,
400 const FunctionProtoType *fpt,
401 const CXXMethodDecl *md) {
402 llvm::SmallVector<CanQualType, 16> argTypes;
403
404 // Add the 'this' pointer.
405 argTypes.push_back(Elt: deriveThisType(rd, md));
406
407 assert(!cir::MissingFeatures::opCallFnInfoOpts());
408 return ::arrangeCIRFunctionInfo(
409 cgt&: *this, prefix&: argTypes,
410 fpt: fpt->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
411}
412
413/// Arrange the argument and result information for the declaration or
414/// definition of the given function.
415const CIRGenFunctionInfo &
416CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
417 if (const auto *md = dyn_cast<CXXMethodDecl>(Val: fd))
418 if (md->isInstance())
419 return arrangeCXXMethodDeclaration(md);
420
421 CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();
422
423 assert(isa<FunctionType>(funcTy));
424 // TODO: setCUDAKernelCallingConvention
425 assert(!cir::MissingFeatures::cudaSupport());
426
427 // When declaring a function without a prototype, always use a non-variadic
428 // type.
429 if (CanQual<FunctionNoProtoType> noProto =
430 funcTy.getAs<FunctionNoProtoType>()) {
431 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
432 assert(!cir::MissingFeatures::opCallFnInfoOpts());
433 return arrangeCIRFunctionInfo(returnType: noProto->getReturnType(), argTypes: {},
434 required: RequiredArgs::All);
435 }
436
437 return arrangeFreeFunctionType(fpt: funcTy.castAs<FunctionProtoType>());
438}
439
440static cir::CIRCallOpInterface
441emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
442 cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
443 cir::FuncOp directFuncOp,
444 const SmallVectorImpl<mlir::Value> &cirCallArgs,
445 const mlir::NamedAttrList &attrs) {
446 CIRGenBuilderTy &builder = cgf.getBuilder();
447
448 assert(!cir::MissingFeatures::opCallSurroundingTry());
449 assert(!cir::MissingFeatures::invokeOp());
450
451 assert(builder.getInsertionBlock() && "expected valid basic block");
452
453 cir::CallOp op;
454 if (indirectFuncTy) {
455 // TODO(cir): Set calling convention for indirect calls.
456 assert(!cir::MissingFeatures::opCallCallConv());
457 op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,
458 cirCallArgs, attrs);
459 } else {
460 op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs);
461 }
462
463 return op;
464}
465
466const CIRGenFunctionInfo &
467CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
468 SmallVector<CanQualType, 16> argTypes;
469 assert(!cir::MissingFeatures::opCallFnInfoOpts());
470 return ::arrangeCIRFunctionInfo(cgt&: *this, prefix&: argTypes, fpt);
471}
472
473const CIRGenFunctionInfo &
474CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
475 CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
476 assert(!cir::MissingFeatures::opCallFnInfoOpts());
477 return arrangeCIRFunctionInfo(returnType: resultType, argTypes: {}, required: RequiredArgs(0));
478}
479
480RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
481 const CIRGenCallee &callee,
482 ReturnValueSlot returnValue,
483 const CallArgList &args,
484 cir::CIRCallOpInterface *callOp,
485 mlir::Location loc) {
486 QualType retTy = funcInfo.getReturnType();
487 cir::FuncType cirFuncTy = getTypes().getFunctionType(funcInfo);
488
489 SmallVector<mlir::Value, 16> cirCallArgs(args.size());
490
491 assert(!cir::MissingFeatures::emitLifetimeMarkers());
492
493 // Translate all of the arguments as necessary to match the CIR lowering.
494 for (auto [argNo, arg, canQualArgType] :
495 llvm::enumerate(First: args, Rest: funcInfo.argTypes())) {
496
497 // Insert a padding argument to ensure proper alignment.
498 assert(!cir::MissingFeatures::opCallPaddingArgs());
499
500 mlir::Type argType = convertType(canQualArgType);
501 if (!mlir::isa<cir::RecordType>(argType)) {
502 mlir::Value v;
503 if (arg.isAggregate())
504 cgm.errorNYI(loc, "emitCall: aggregate call argument");
505 v = arg.getKnownRValue().getValue();
506
507 // We might have to widen integers, but we should never truncate.
508 if (argType != v.getType() && mlir::isa<cir::IntType>(v.getType()))
509 cgm.errorNYI(loc, "emitCall: widening integer call argument");
510
511 // If the argument doesn't match, perform a bitcast to coerce it. This
512 // can happen due to trivial type mismatches.
513 // TODO(cir): When getFunctionType is added, assert that this isn't
514 // needed.
515 assert(!cir::MissingFeatures::opCallBitcastArg());
516 cirCallArgs[argNo] = v;
517 } else {
518 Address src = Address::invalid();
519 if (!arg.isAggregate())
520 cgm.errorNYI(loc, "emitCall: non-aggregate call argument");
521 else
522 src = arg.hasLValue() ? arg.getKnownLValue().getAddress()
523 : arg.getKnownRValue().getAggregateAddress();
524
525 // Fast-isel and the optimizer generally like scalar values better than
526 // FCAs, so we flatten them if this is safe to do for this argument.
527 auto argRecordTy = cast<cir::RecordType>(argType);
528 mlir::Type srcTy = src.getElementType();
529 // FIXME(cir): get proper location for each argument.
530 mlir::Location argLoc = loc;
531
532 // If the source type is smaller than the destination type of the
533 // coerce-to logic, copy the source value into a temp alloca the size
534 // of the destination type to allow loading all of it. The bits past
535 // the source value are left undef.
536 // FIXME(cir): add data layout info and compare sizes instead of
537 // matching the types.
538 //
539 // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
540 // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
541 // if (SrcSize < DstSize) {
542 assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());
543 if (srcTy != argRecordTy) {
544 cgm.errorNYI(loc, "emitCall: source type does not match argument type");
545 } else {
546 // FIXME(cir): this currently only runs when the types are exactly the
547 // same, but should be when alloc sizes are the same, fix this as soon
548 // as datalayout gets introduced.
549 assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());
550 }
551
552 // assert(NumCIRArgs == STy.getMembers().size());
553 // In LLVMGen: Still only pass the struct without any gaps but mark it
554 // as such somehow.
555 //
556 // In CIRGen: Emit a load from the "whole" struct,
557 // which shall be broken later by some lowering step into multiple
558 // loads.
559 assert(!cir::MissingFeatures::lowerAggregateLoadStore());
560 cirCallArgs[argNo] = builder.createLoad(argLoc, src);
561 }
562 }
563
564 const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(cgf&: *this);
565 mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
566
567 assert(!cir::MissingFeatures::opCallInAlloca());
568
569 mlir::NamedAttrList attrs;
570 StringRef funcName;
571 if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
572 funcName = calleeFuncOp.getName();
573
574 assert(!cir::MissingFeatures::opCallCallConv());
575 assert(!cir::MissingFeatures::opCallAttrs());
576 cgm.constructAttributeList(callee.getAbstractInfo(), attrs);
577
578 assert(!cir::MissingFeatures::invokeOp());
579
580 cir::FuncType indirectFuncTy;
581 mlir::Value indirectFuncVal;
582 cir::FuncOp directFuncOp;
583 if (auto fnOp = dyn_cast<cir::FuncOp>(calleePtr)) {
584 directFuncOp = fnOp;
585 } else {
586 [[maybe_unused]] mlir::ValueTypeRange<mlir::ResultRange> resultTypes =
587 calleePtr->getResultTypes();
588 [[maybe_unused]] auto funcPtrTy =
589 mlir::dyn_cast<cir::PointerType>(resultTypes.front());
590 assert(funcPtrTy && mlir::isa<cir::FuncType>(funcPtrTy.getPointee()) &&
591 "expected pointer to function");
592
593 indirectFuncTy = cirFuncTy;
594 indirectFuncVal = calleePtr->getResult(0);
595 }
596
597 mlir::Location callLoc = loc;
598 cir::CIRCallOpInterface theCall =
599 emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
600 cirCallArgs, attrs);
601
602 if (callOp)
603 *callOp = theCall;
604
605 assert(!cir::MissingFeatures::opCallMustTail());
606 assert(!cir::MissingFeatures::opCallReturn());
607
608 mlir::Type retCIRTy = convertType(retTy);
609 if (isa<cir::VoidType>(retCIRTy))
610 return getUndefRValue(ty: retTy);
611 switch (getEvaluationKind(type: retTy)) {
612 case cir::TEK_Aggregate: {
613 Address destPtr = returnValue.getValue();
614
615 if (!destPtr.isValid())
616 destPtr = createMemTemp(retTy, callLoc, getCounterAggTmpAsString());
617
618 mlir::ResultRange results = theCall->getOpResults();
619 assert(results.size() <= 1 && "multiple returns from a call");
620
621 SourceLocRAIIObject loc{*this, callLoc};
622 emitAggregateStore(results[0], destPtr);
623 return RValue::getAggregate(addr: destPtr);
624 }
625 case cir::TEK_Scalar: {
626 mlir::ResultRange results = theCall->getOpResults();
627 assert(results.size() == 1 && "unexpected number of returns");
628
629 // If the argument doesn't match, perform a bitcast to coerce it. This
630 // can happen due to trivial type mismatches.
631 if (results[0].getType() != retCIRTy)
632 cgm.errorNYI(loc, "bitcast on function return value");
633
634 mlir::Region *region = builder.getBlock()->getParent();
635 if (region != theCall->getParentRegion())
636 cgm.errorNYI(loc, "function calls with cleanup");
637
638 return RValue::get(results[0]);
639 }
640 case cir::TEK_Complex:
641 cgm.errorNYI(loc, "unsupported evaluation kind of function call result");
642 return getUndefRValue(ty: retTy);
643 }
644 llvm_unreachable("Invalid evaluation kind");
645}
646
647void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
648 clang::QualType argType) {
649 assert(argType->isReferenceType() == e->isGLValue() &&
650 "reference binding to unmaterialized r-value!");
651
652 if (e->isGLValue()) {
653 assert(e->getObjectKind() == OK_Ordinary);
654 return args.add(rvalue: emitReferenceBindingToExpr(e), type: argType);
655 }
656
657 bool hasAggregateEvalKind = hasAggregateEvaluationKind(type: argType);
658
659 // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
660 // However, we still have to push an EH-only cleanup in case we unwind before
661 // we make it to the call.
662 if (argType->isRecordType() &&
663 argType->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
664 assert(!cir::MissingFeatures::msabi());
665 cgm.errorNYI(e->getSourceRange(), "emitCallArg: msabi is NYI");
666 }
667
668 if (hasAggregateEvalKind && isa<ImplicitCastExpr>(Val: e) &&
669 cast<CastExpr>(Val: e)->getCastKind() == CK_LValueToRValue) {
670 LValue lv = emitLValue(e: cast<CastExpr>(Val: e)->getSubExpr());
671 assert(lv.isSimple());
672 args.addUncopiedAggregate(lvalue: lv, type: argType);
673 return;
674 }
675
676 args.add(rvalue: emitAnyExprToTemp(e), type: argType);
677}
678
679QualType CIRGenFunction::getVarArgType(const Expr *arg) {
680 // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
681 // implicitly widens null pointer constants that are arguments to varargs
682 // functions to pointer-sized ints.
683 if (!getTarget().getTriple().isOSWindows())
684 return arg->getType();
685
686 assert(!cir::MissingFeatures::msabi());
687 cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");
688 return arg->getType();
689}
690
691/// Similar to emitAnyExpr(), however, the result will always be accessible
692/// even if no aggregate location is provided.
693RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) {
694 AggValueSlot aggSlot = AggValueSlot::ignored();
695
696 if (hasAggregateEvaluationKind(e->getType()))
697 aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()),
698 getCounterAggTmpAsString());
699
700 return emitAnyExpr(e, aggSlot);
701}
702
703void CIRGenFunction::emitCallArgs(
704 CallArgList &args, PrototypeWrapper prototype,
705 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
706 AbstractCallee callee, unsigned paramsToSkip) {
707 llvm::SmallVector<QualType, 16> argTypes;
708
709 assert(!cir::MissingFeatures::opCallCallConv());
710
711 // First, if a prototype was provided, use those argument types.
712 bool isVariadic = false;
713 if (prototype.p) {
714 assert(!cir::MissingFeatures::opCallObjCMethod());
715
716 const auto *fpt = cast<const FunctionProtoType *>(Val&: prototype.p);
717 isVariadic = fpt->isVariadic();
718 assert(!cir::MissingFeatures::opCallCallConv());
719 argTypes.assign(in_start: fpt->param_type_begin() + paramsToSkip,
720 in_end: fpt->param_type_end());
721 }
722
723 // If we still have any arguments, emit them using the type of the argument.
724 for (const clang::Expr *a : llvm::drop_begin(RangeOrContainer&: argRange, N: argTypes.size()))
725 argTypes.push_back(Elt: isVariadic ? getVarArgType(arg: a) : a->getType());
726 assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));
727
728 // We must evaluate arguments from right to left in the MS C++ ABI, because
729 // arguments are destroyed left to right in the callee. As a special case,
730 // there are certain language constructs taht require left-to-right
731 // evaluation, and in those cases we consider the evaluation order requirement
732 // to trump the "destruction order is reverse construction order" guarantee.
733 auto leftToRight = true;
734 assert(!cir::MissingFeatures::msabi());
735
736 auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,
737 RValue emittedArg) {
738 if (!callee.hasFunctionDecl() || i >= callee.getNumParams())
739 return;
740 auto *ps = callee.getParamDecl(I: i)->getAttr<PassObjectSizeAttr>();
741 if (!ps)
742 return;
743
744 assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
745 cgm.errorNYI(feature: "emit implicit object size for call arg");
746 };
747
748 // Evaluate each argument in the appropriate order.
749 size_t callArgsStart = args.size();
750 for (size_t i = 0; i != argTypes.size(); ++i) {
751 size_t idx = leftToRight ? i : argTypes.size() - i - 1;
752 CallExpr::const_arg_iterator currentArg = argRange.begin() + idx;
753 size_t initialArgSize = args.size();
754
755 emitCallArg(args, e: *currentArg, argType: argTypes[idx]);
756
757 // In particular, we depend on it being the last arg in Args, and the
758 // objectsize bits depend on there only being one arg if !LeftToRight.
759 assert(initialArgSize + 1 == args.size() &&
760 "The code below depends on only adding one arg per emitCallArg");
761 (void)initialArgSize;
762
763 // Since pointer argument are never emitted as LValue, it is safe to emit
764 // non-null argument check for r-value only.
765 if (!args.back().hasLValue()) {
766 RValue rvArg = args.back().getKnownRValue();
767 assert(!cir::MissingFeatures::sanitizers());
768 maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);
769 }
770
771 if (!leftToRight)
772 std::reverse(first: args.begin() + callArgsStart, last: args.end());
773 }
774}
775

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