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 | |
20 | using namespace clang; |
21 | using namespace clang::CIRGen; |
22 | |
23 | CIRGenFunctionInfo * |
24 | CIRGenFunctionInfo::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 | |
45 | cir::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 | |
58 | CIRGenCallee 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. |
64 | static 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 |
73 | static 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 | |
86 | const CIRGenFunctionInfo & |
87 | CIRGenTypes::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. |
132 | CanQualType 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. |
153 | static const CIRGenFunctionInfo & |
154 | arrangeCIRFunctionInfo(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 | |
165 | static const CIRGenFunctionInfo & |
166 | arrangeFreeFunctionLikeCall(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. |
197 | const 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`. |
235 | const 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 | |
254 | const CIRGenFunctionInfo & |
255 | CIRGenTypes::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. |
263 | const CIRGenFunctionInfo & |
264 | CIRGenTypes::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. |
286 | const CIRGenFunctionInfo & |
287 | CIRGenTypes::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. |
303 | const CIRGenFunctionInfo & |
304 | CIRGenTypes::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 | |
328 | static cir::CIRCallOpInterface |
329 | emitCallLikeOp(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 | |
350 | const CIRGenFunctionInfo & |
351 | CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) { |
352 | SmallVector<CanQualType, 16> argTypes; |
353 | assert(!cir::MissingFeatures::opCallFnInfoOpts()); |
354 | return ::arrangeCIRFunctionInfo(cgt&: *this, prefix&: argTypes, fpt); |
355 | } |
356 | |
357 | const CIRGenFunctionInfo & |
358 | CIRGenTypes::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 | |
364 | RValue 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 | |
478 | void 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 | |
499 | QualType 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. |
513 | RValue 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 | |
522 | void 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 | |