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
63/// Returns the canonical formal type of the given C++ method.
64static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {
65 return md->getType()
66 ->getCanonicalTypeUnqualified()
67 .getAs<FunctionProtoType>();
68}
69
70/// Adds the formal parameters in FPT to the given prefix. If any parameter in
71/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
72/// TODO(cir): this should be shared with LLVM codegen
73static void appendParameterTypes(const CIRGenTypes &cgt,
74 SmallVectorImpl<CanQualType> &prefix,
75 CanQual<FunctionProtoType> fpt) {
76 assert(!cir::MissingFeatures::opCallExtParameterInfo());
77 // Fast path: don't touch param info if we don't need to.
78 if (!fpt->hasExtParameterInfos()) {
79 prefix.append(fpt->param_type_begin(), fpt->param_type_end());
80 return;
81 }
82
83 cgt.getCGModule().errorNYI(feature: "appendParameterTypes: hasExtParameterInfos");
84}
85
86const CIRGenFunctionInfo &
87CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) {
88 auto *md = cast<CXXMethodDecl>(Val: gd.getDecl());
89
90 llvm::SmallVector<CanQualType, 16> argTypes;
91 argTypes.push_back(Elt: deriveThisType(rd: md->getParent(), md));
92
93 bool passParams = true;
94
95 if (auto *cd = dyn_cast<CXXConstructorDecl>(Val: md)) {
96 // A base class inheriting constructor doesn't get forwarded arguments
97 // needed to construct a virtual base (or base class thereof)
98 if (cd->getInheritedConstructor())
99 cgm.errorNYI(cd->getSourceRange(),
100 "arrangeCXXStructorDeclaration: inheriting constructor");
101 }
102
103 CanQual<FunctionProtoType> fpt = getFormalType(md);
104
105 if (passParams)
106 appendParameterTypes(cgt: *this, prefix&: argTypes, fpt);
107
108 assert(!cir::MissingFeatures::implicitConstructorArgs());
109
110 RequiredArgs required =
111 (passParams && md->isVariadic() ? RequiredArgs(argTypes.size())
112 : RequiredArgs::All);
113
114 CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front()
115 : theCXXABI.hasMostDerivedReturn(gd)
116 ? astContext.VoidPtrTy
117 : astContext.VoidTy;
118
119 assert(!theCXXABI.hasThisReturn(gd) &&
120 "Please send PR with a test and remove this");
121
122 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
123 assert(!cir::MissingFeatures::opCallFnInfoOpts());
124
125 return arrangeCIRFunctionInfo(returnType: resultType, argTypes, required);
126}
127
128/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
129/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
130/// indicates that there is no meaningful 'this' type, and a null `md` can occur
131/// when calling a method pointer.
132CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd,
133 const CXXMethodDecl *md) {
134 QualType recTy;
135 if (rd) {
136 recTy = getASTContext().getTagDeclType(rd)->getCanonicalTypeInternal();
137 } else {
138 // This can happen with the MS ABI. It shouldn't need anything more than
139 // setting recTy to VoidTy here, but we're flagging it for now because we
140 // don't have the full handling implemented.
141 cgm.errorNYI(feature: "deriveThisType: no record decl");
142 recTy = getASTContext().VoidTy;
143 }
144
145 if (md)
146 recTy = getASTContext().getAddrSpaceQualType(
147 T: recTy, AddressSpace: md->getMethodQualifiers().getAddressSpace());
148 return getASTContext().getPointerType(T: CanQualType::CreateUnsafe(Other: recTy));
149}
150
151/// Arrange the CIR function layout for a value of the given function type, on
152/// top of any implicit parameters already stored.
153static const CIRGenFunctionInfo &
154arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl<CanQualType> &prefix,
155 CanQual<FunctionProtoType> fpt) {
156 assert(!cir::MissingFeatures::opCallFnInfoOpts());
157 RequiredArgs required =
158 RequiredArgs::getFromProtoWithExtraSlots(prototype: fpt, additional: prefix.size());
159 assert(!cir::MissingFeatures::opCallExtParameterInfo());
160 appendParameterTypes(cgt, prefix, fpt);
161 CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
162 return cgt.arrangeCIRFunctionInfo(returnType: resultType, argTypes: prefix, required);
163}
164
165static const CIRGenFunctionInfo &
166arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
167 const CallArgList &args,
168 const FunctionType *fnType) {
169
170 RequiredArgs required = RequiredArgs::All;
171
172 if (const auto *proto = dyn_cast<FunctionProtoType>(Val: fnType)) {
173 if (proto->isVariadic())
174 required = RequiredArgs::getFromProtoWithExtraSlots(prototype: proto, additional: 0);
175 if (proto->hasExtParameterInfos())
176 cgm.errorNYI(feature: "call to functions with extra parameter info");
177 } else if (cgm.getTargetCIRGenInfo().isNoProtoCallVariadic(
178 fnType: cast<FunctionNoProtoType>(Val: fnType)))
179 cgm.errorNYI(feature: "call to function without a prototype");
180
181 SmallVector<CanQualType, 16> argTypes;
182 for (const CallArg &arg : args)
183 argTypes.push_back(Elt: cgt.getASTContext().getCanonicalParamType(T: arg.ty));
184
185 CanQualType retType = fnType->getReturnType()
186 ->getCanonicalTypeUnqualified()
187 .getUnqualifiedType();
188
189 assert(!cir::MissingFeatures::opCallFnInfoOpts());
190 return cgt.arrangeCIRFunctionInfo(returnType: retType, argTypes, required);
191}
192
193/// Arrange a call to a C++ method, passing the given arguments.
194///
195/// passProtoArgs indicates whether `args` has args for the parameters in the
196/// given CXXConstructorDecl.
197const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall(
198 const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind,
199 bool passProtoArgs) {
200
201 // FIXME: Kill copy.
202 llvm::SmallVector<CanQualType, 16> argTypes;
203 for (const auto &arg : args)
204 argTypes.push_back(Elt: astContext.getCanonicalParamType(T: arg.ty));
205
206 assert(!cir::MissingFeatures::implicitConstructorArgs());
207 // +1 for implicit this, which should always be args[0]
208 unsigned totalPrefixArgs = 1;
209
210 CanQual<FunctionProtoType> fpt = getFormalType(d);
211 RequiredArgs required =
212 passProtoArgs
213 ? RequiredArgs::getFromProtoWithExtraSlots(prototype: fpt, additional: totalPrefixArgs)
214 : RequiredArgs::All;
215
216 GlobalDecl gd(d, ctorKind);
217 if (theCXXABI.hasThisReturn(gd))
218 cgm.errorNYI(d->getSourceRange(),
219 "arrangeCXXConstructorCall: hasThisReturn");
220 if (theCXXABI.hasMostDerivedReturn(gd))
221 cgm.errorNYI(d->getSourceRange(),
222 "arrangeCXXConstructorCall: hasMostDerivedReturn");
223 CanQualType resultType = astContext.VoidTy;
224
225 assert(!cir::MissingFeatures::opCallFnInfoOpts());
226 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
227
228 return arrangeCIRFunctionInfo(returnType: resultType, argTypes, required);
229}
230
231/// Arrange a call to a C++ method, passing the given arguments.
232///
233/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
234/// does not count `this`.
235const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXMethodCall(
236 const CallArgList &args, const FunctionProtoType *proto,
237 RequiredArgs required, unsigned numPrefixArgs) {
238 assert(!cir::MissingFeatures::opCallExtParameterInfo());
239 assert(numPrefixArgs + 1 <= args.size() &&
240 "Emitting a call with less args than the required prefix?");
241
242 // FIXME: Kill copy.
243 llvm::SmallVector<CanQualType, 16> argTypes;
244 for (const CallArg &arg : args)
245 argTypes.push_back(Elt: astContext.getCanonicalParamType(T: arg.ty));
246
247 assert(!cir::MissingFeatures::opCallFnInfoOpts());
248 return arrangeCIRFunctionInfo(returnType: proto->getReturnType()
249 ->getCanonicalTypeUnqualified()
250 .getUnqualifiedType(),
251 argTypes, required);
252}
253
254const CIRGenFunctionInfo &
255CIRGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
256 const FunctionType *fnType) {
257 return arrangeFreeFunctionLikeCall(cgt&: *this, cgm, args, fnType);
258}
259
260/// Arrange the argument and result information for a declaration or definition
261/// of the given C++ non-static member function. The member function must be an
262/// ordinary function, i.e. not a constructor or destructor.
263const CIRGenFunctionInfo &
264CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) {
265 assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
266 assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
267
268 auto prototype =
269 md->getType()->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
270 assert(!cir::MissingFeatures::cudaSupport());
271
272 if (md->isInstance()) {
273 // The abstract case is perfectly fine.
274 auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
275 return arrangeCXXMethodType(rd: thisType, ftp: prototype.getTypePtr(), md);
276 }
277
278 return arrangeFreeFunctionType(prototype);
279}
280
281/// Arrange the argument and result information for a call to an unknown C++
282/// non-static member function of the given abstract type. (A null RD means we
283/// don't have any meaningful "this" argument type, so fall back to a generic
284/// pointer type). The member fucntion must be an ordinary function, i.e. not a
285/// constructor or destructor.
286const CIRGenFunctionInfo &
287CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd,
288 const FunctionProtoType *fpt,
289 const CXXMethodDecl *md) {
290 llvm::SmallVector<CanQualType, 16> argTypes;
291
292 // Add the 'this' pointer.
293 argTypes.push_back(Elt: deriveThisType(rd, md));
294
295 assert(!cir::MissingFeatures::opCallFnInfoOpts());
296 return ::arrangeCIRFunctionInfo(
297 cgt&: *this, prefix&: argTypes,
298 fpt: fpt->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
299}
300
301/// Arrange the argument and result information for the declaration or
302/// definition of the given function.
303const CIRGenFunctionInfo &
304CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) {
305 if (const auto *md = dyn_cast<CXXMethodDecl>(Val: fd))
306 if (md->isInstance())
307 return arrangeCXXMethodDeclaration(md);
308
309 CanQualType funcTy = fd->getType()->getCanonicalTypeUnqualified();
310
311 assert(isa<FunctionType>(funcTy));
312 // TODO: setCUDAKernelCallingConvention
313 assert(!cir::MissingFeatures::cudaSupport());
314
315 // When declaring a function without a prototype, always use a non-variadic
316 // type.
317 if (CanQual<FunctionNoProtoType> noProto =
318 funcTy.getAs<FunctionNoProtoType>()) {
319 assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
320 assert(!cir::MissingFeatures::opCallFnInfoOpts());
321 return arrangeCIRFunctionInfo(noProto->getReturnType(), std::nullopt,
322 RequiredArgs::All);
323 }
324
325 return arrangeFreeFunctionType(fpt: funcTy.castAs<FunctionProtoType>());
326}
327
328static cir::CIRCallOpInterface
329emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
330 cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
331 cir::FuncOp directFuncOp,
332 const SmallVectorImpl<mlir::Value> &cirCallArgs) {
333 CIRGenBuilderTy &builder = cgf.getBuilder();
334
335 assert(!cir::MissingFeatures::opCallSurroundingTry());
336 assert(!cir::MissingFeatures::invokeOp());
337
338 assert(builder.getInsertionBlock() && "expected valid basic block");
339
340 if (indirectFuncTy) {
341 // TODO(cir): Set calling convention for indirect calls.
342 assert(!cir::MissingFeatures::opCallCallConv());
343 return builder.createIndirectCallOp(callLoc, indirectFuncVal,
344 indirectFuncTy, cirCallArgs);
345 }
346
347 return builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
348}
349
350const CIRGenFunctionInfo &
351CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
352 SmallVector<CanQualType, 16> argTypes;
353 assert(!cir::MissingFeatures::opCallFnInfoOpts());
354 return ::arrangeCIRFunctionInfo(cgt&: *this, prefix&: argTypes, fpt);
355}
356
357const CIRGenFunctionInfo &
358CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
359 CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
360 assert(!cir::MissingFeatures::opCallFnInfoOpts());
361 return arrangeCIRFunctionInfo(returnType: resultType, argTypes: {}, required: RequiredArgs(0));
362}
363
364RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
365 const CIRGenCallee &callee,
366 ReturnValueSlot returnValue,
367 const CallArgList &args,
368 cir::CIRCallOpInterface *callOp,
369 mlir::Location loc) {
370 QualType retTy = funcInfo.getReturnType();
371 cir::FuncType cirFuncTy = getTypes().getFunctionType(funcInfo);
372
373 SmallVector<mlir::Value, 16> cirCallArgs(args.size());
374
375 assert(!cir::MissingFeatures::emitLifetimeMarkers());
376
377 // Translate all of the arguments as necessary to match the CIR lowering.
378 for (auto [argNo, arg, canQualArgType] :
379 llvm::enumerate(First: args, Rest: funcInfo.argTypes())) {
380
381 // Insert a padding argument to ensure proper alignment.
382 assert(!cir::MissingFeatures::opCallPaddingArgs());
383
384 mlir::Type argType = convertType(canQualArgType);
385 if (!mlir::isa<cir::RecordType>(argType)) {
386 mlir::Value v;
387 if (arg.isAggregate())
388 cgm.errorNYI(loc, "emitCall: aggregate call argument");
389 v = arg.getKnownRValue().getScalarVal();
390
391 // We might have to widen integers, but we should never truncate.
392 if (argType != v.getType() && mlir::isa<cir::IntType>(v.getType()))
393 cgm.errorNYI(loc, "emitCall: widening integer call argument");
394
395 // If the argument doesn't match, perform a bitcast to coerce it. This
396 // can happen due to trivial type mismatches.
397 // TODO(cir): When getFunctionType is added, assert that this isn't
398 // needed.
399 assert(!cir::MissingFeatures::opCallBitcastArg());
400 cirCallArgs[argNo] = v;
401 } else {
402 assert(!cir::MissingFeatures::opCallAggregateArgs());
403 cgm.errorNYI(feature: "emitCall: aggregate function call argument");
404 }
405 }
406
407 const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(cgf&: *this);
408 mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
409
410 assert(!cir::MissingFeatures::opCallInAlloca());
411
412 mlir::NamedAttrList attrs;
413 StringRef funcName;
414 if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
415 funcName = calleeFuncOp.getName();
416
417 assert(!cir::MissingFeatures::opCallCallConv());
418 assert(!cir::MissingFeatures::opCallSideEffect());
419 assert(!cir::MissingFeatures::opCallAttrs());
420
421 assert(!cir::MissingFeatures::invokeOp());
422
423 cir::FuncType indirectFuncTy;
424 mlir::Value indirectFuncVal;
425 cir::FuncOp directFuncOp;
426 if (auto fnOp = dyn_cast<cir::FuncOp>(calleePtr)) {
427 directFuncOp = fnOp;
428 } else {
429 [[maybe_unused]] mlir::ValueTypeRange<mlir::ResultRange> resultTypes =
430 calleePtr->getResultTypes();
431 [[maybe_unused]] auto funcPtrTy =
432 mlir::dyn_cast<cir::PointerType>(resultTypes.front());
433 assert(funcPtrTy && mlir::isa<cir::FuncType>(funcPtrTy.getPointee()) &&
434 "expected pointer to function");
435
436 indirectFuncTy = cirFuncTy;
437 indirectFuncVal = calleePtr->getResult(0);
438 }
439
440 assert(!cir::MissingFeatures::opCallAttrs());
441
442 cir::CIRCallOpInterface theCall = emitCallLikeOp(
443 *this, loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs);
444
445 if (callOp)
446 *callOp = theCall;
447
448 assert(!cir::MissingFeatures::opCallMustTail());
449 assert(!cir::MissingFeatures::opCallReturn());
450
451 mlir::Type retCIRTy = convertType(retTy);
452 if (isa<cir::VoidType>(retCIRTy))
453 return getUndefRValue(ty: retTy);
454 switch (getEvaluationKind(type: retTy)) {
455 case cir::TEK_Scalar: {
456 mlir::ResultRange results = theCall->getOpResults();
457 assert(results.size() == 1 && "unexpected number of returns");
458
459 // If the argument doesn't match, perform a bitcast to coerce it. This
460 // can happen due to trivial type mismatches.
461 if (results[0].getType() != retCIRTy)
462 cgm.errorNYI(loc, "bitcast on function return value");
463
464 mlir::Region *region = builder.getBlock()->getParent();
465 if (region != theCall->getParentRegion())
466 cgm.errorNYI(loc, "function calls with cleanup");
467
468 return RValue::get(results[0]);
469 }
470 case cir::TEK_Complex:
471 case cir::TEK_Aggregate:
472 cgm.errorNYI(loc, "unsupported evaluation kind of function call result");
473 return getUndefRValue(ty: retTy);
474 }
475 llvm_unreachable("Invalid evaluation kind");
476}
477
478void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
479 clang::QualType argType) {
480 assert(argType->isReferenceType() == e->isGLValue() &&
481 "reference binding to unmaterialized r-value!");
482
483 if (e->isGLValue()) {
484 assert(e->getObjectKind() == OK_Ordinary);
485 return args.add(rvalue: emitReferenceBindingToExpr(e), type: argType);
486 }
487
488 bool hasAggregateEvalKind = hasAggregateEvaluationKind(type: argType);
489
490 if (hasAggregateEvalKind) {
491 assert(!cir::MissingFeatures::opCallAggregateArgs());
492 cgm.errorNYI(e->getSourceRange(),
493 "emitCallArg: aggregate function call argument");
494 }
495
496 args.add(rvalue: emitAnyExprToTemp(e), type: argType);
497}
498
499QualType CIRGenFunction::getVarArgType(const Expr *arg) {
500 // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
501 // implicitly widens null pointer constants that are arguments to varargs
502 // functions to pointer-sized ints.
503 if (!getTarget().getTriple().isOSWindows())
504 return arg->getType();
505
506 assert(!cir::MissingFeatures::msabi());
507 cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");
508 return arg->getType();
509}
510
511/// Similar to emitAnyExpr(), however, the result will always be accessible
512/// even if no aggregate location is provided.
513RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) {
514 assert(!cir::MissingFeatures::opCallAggregateArgs());
515
516 if (hasAggregateEvaluationKind(type: e->getType()))
517 cgm.errorNYI(e->getSourceRange(), "emit aggregate value to temp");
518
519 return emitAnyExpr(e);
520}
521
522void CIRGenFunction::emitCallArgs(
523 CallArgList &args, PrototypeWrapper prototype,
524 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
525 AbstractCallee callee, unsigned paramsToSkip) {
526 llvm::SmallVector<QualType, 16> argTypes;
527
528 assert(!cir::MissingFeatures::opCallCallConv());
529
530 // First, if a prototype was provided, use those argument types.
531 bool isVariadic = false;
532 if (prototype.p) {
533 assert(!cir::MissingFeatures::opCallObjCMethod());
534
535 const auto *fpt = cast<const FunctionProtoType *>(Val&: prototype.p);
536 isVariadic = fpt->isVariadic();
537 assert(!cir::MissingFeatures::opCallCallConv());
538 argTypes.assign(in_start: fpt->param_type_begin() + paramsToSkip,
539 in_end: fpt->param_type_end());
540 }
541
542 // If we still have any arguments, emit them using the type of the argument.
543 for (const clang::Expr *a : llvm::drop_begin(argRange, argTypes.size()))
544 argTypes.push_back(isVariadic ? getVarArgType(a) : a->getType());
545 assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));
546
547 // We must evaluate arguments from right to left in the MS C++ ABI, because
548 // arguments are destroyed left to right in the callee. As a special case,
549 // there are certain language constructs taht require left-to-right
550 // evaluation, and in those cases we consider the evaluation order requirement
551 // to trump the "destruction order is reverse construction order" guarantee.
552 auto leftToRight = true;
553 assert(!cir::MissingFeatures::msabi());
554
555 auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,
556 RValue emittedArg) {
557 if (!callee.hasFunctionDecl() || i >= callee.getNumParams())
558 return;
559 auto *ps = callee.getParamDecl(i)->getAttr<PassObjectSizeAttr>();
560 if (!ps)
561 return;
562
563 assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs());
564 cgm.errorNYI(feature: "emit implicit object size for call arg");
565 };
566
567 // Evaluate each argument in the appropriate order.
568 size_t callArgsStart = args.size();
569 for (size_t i = 0; i != argTypes.size(); ++i) {
570 size_t idx = leftToRight ? i : argTypes.size() - i - 1;
571 CallExpr::const_arg_iterator currentArg = argRange.begin() + idx;
572 size_t initialArgSize = args.size();
573
574 emitCallArg(args, e: *currentArg, argType: argTypes[idx]);
575
576 // In particular, we depend on it being the last arg in Args, and the
577 // objectsize bits depend on there only being one arg if !LeftToRight.
578 assert(initialArgSize + 1 == args.size() &&
579 "The code below depends on only adding one arg per emitCallArg");
580 (void)initialArgSize;
581
582 // Since pointer argument are never emitted as LValue, it is safe to emit
583 // non-null argument check for r-value only.
584 if (!args.back().hasLValue()) {
585 RValue rvArg = args.back().getKnownRValue();
586 assert(!cir::MissingFeatures::sanitizers());
587 maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);
588 }
589
590 if (!leftToRight)
591 std::reverse(first: args.begin() + callArgsStart, last: args.end());
592 }
593}
594

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