clang 23.0.0git
CIRGenCall.cpp
Go to the documentation of this file.
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"
19
20using namespace clang;
21using namespace clang::CIRGen;
22
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>(argTypes.size() + 1));
30
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(argTypes.begin(), argTypes.end(), fi->argTypesBegin());
41
42 return fi;
43}
44
49
51 mlir::Type resultType = convertType(info.getReturnType());
53 argTypes.reserve(info.getNumRequiredArgs());
54
55 for (const CanQualType &argType : info.requiredArguments())
56 argTypes.push_back(convertType(argType));
57
58 return cir::FuncType::get(argTypes,
59 (resultType ? resultType : builder.getVoidTy()),
60 info.isVariadic());
61}
62
65 const FunctionProtoType *fpt = md->getType()->getAs<FunctionProtoType>();
66
67 if (!isFuncTypeConvertible(fpt))
68 cgm.errorNYI("getFunctionTypeForVTable: non-convertible function type");
69
70 return getFunctionType(gd);
71}
72
74 if (isVirtual()) {
75 const CallExpr *ce = getVirtualCallExpr();
78 ce ? ce->getBeginLoc() : SourceLocation());
79 }
80 return *this;
81}
82
83void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {
84 // In classic codegen:
85 // Function to store a first-class aggregate into memory. We prefer to
86 // store the elements rather than the aggregate to be more friendly to
87 // fast-isel.
88 // In CIR codegen:
89 // Emit the most simple cir.store possible (e.g. a store for a whole
90 // record), which can later be broken down in other CIR levels (or prior
91 // to dialect codegen).
92
93 // Stored result for the callers of this function expected to be in the same
94 // scope as the value, don't make assumptions about current insertion point.
95 mlir::OpBuilder::InsertionGuard guard(builder);
96 builder.setInsertionPointAfter(value.getDefiningOp());
97 builder.createStore(*currSrcLoc, value, dest);
98}
99
101 mlir::NamedAttrList &attrs,
102 const FunctionProtoType *fpt) {
103 if (!fpt)
104 return;
105
107 fpt->isNothrow())
108 attrs.set(cir::CIRDialect::getNoThrowAttrName(),
109 mlir::UnitAttr::get(builder.getContext()));
110}
111
112/// Construct the CIR attribute list of a function or call.
113void CIRGenModule::constructAttributeList(llvm::StringRef name,
114 const CIRGenFunctionInfo &info,
115 CIRGenCalleeInfo calleeInfo,
116 mlir::NamedAttrList &attrs,
117 cir::CallingConv &callingConv,
118 cir::SideEffect &sideEffect,
119 bool attrOnCallSite, bool isThunk) {
121 sideEffect = cir::SideEffect::All;
122
124 calleeInfo.getCalleeFunctionProtoType());
125
126 const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
127
128 if (targetDecl) {
129 if (targetDecl->hasAttr<NoThrowAttr>())
130 attrs.set(cir::CIRDialect::getNoThrowAttrName(),
131 mlir::UnitAttr::get(&getMLIRContext()));
132
133 if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
135 getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
137 }
138
140
141 // 'const', 'pure' and 'noalias' attributed functions are also nounwind.
142 if (targetDecl->hasAttr<ConstAttr>()) {
143 // gcc specifies that 'const' functions have greater restrictions than
144 // 'pure' functions, so they also cannot have infinite loops.
145 sideEffect = cir::SideEffect::Const;
146 } else if (targetDecl->hasAttr<PureAttr>()) {
147 // gcc specifies that 'pure' functions cannot have infinite loops.
148 sideEffect = cir::SideEffect::Pure;
149 }
150
152 }
153
155
156 attrs.set(cir::CIRDialect::getSideEffectAttrName(),
157 cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
158}
159
160/// Returns the canonical formal type of the given C++ method.
166
167/// Adds the formal parameters in FPT to the given prefix. If any parameter in
168/// FPT has pass_object_size_attrs, then we'll add parameters for those, too.
169/// TODO(cir): this should be shared with LLVM codegen
170static void appendParameterTypes(const CIRGenTypes &cgt,
174 // Fast path: don't touch param info if we don't need to.
175 if (!fpt->hasExtParameterInfos()) {
176 prefix.append(fpt->param_type_begin(), fpt->param_type_end());
177 return;
178 }
179
180 cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos");
181}
182
183const CIRGenFunctionInfo &
185 auto *md = cast<CXXMethodDecl>(gd.getDecl());
186
188 argTypes.push_back(deriveThisType(md->getParent(), md));
189
190 bool passParams = true;
191
192 if (auto *cd = dyn_cast<CXXConstructorDecl>(md)) {
193 // A base class inheriting constructor doesn't get forwarded arguments
194 // needed to construct a virtual base (or base class thereof)
195 if (cd->getInheritedConstructor())
196 cgm.errorNYI(cd->getSourceRange(),
197 "arrangeCXXStructorDeclaration: inheriting constructor");
198 }
199
201
202 if (passParams)
203 appendParameterTypes(*this, argTypes, fpt);
204
205 // The structor signature may include implicit parameters.
206 [[maybe_unused]] CIRGenCXXABI::AddedStructorArgCounts addedArgs =
207 theCXXABI.buildStructorSignature(gd, argTypes);
209
210 RequiredArgs required =
211 (passParams && md->isVariadic() ? RequiredArgs(argTypes.size())
213
214 CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front()
215 : theCXXABI.hasMostDerivedReturn(gd)
216 ? astContext.VoidPtrTy
217 : astContext.VoidTy;
218
219 assert(!theCXXABI.hasThisReturn(gd) &&
220 "Please send PR with a test and remove this");
221
224
225 return arrangeCIRFunctionInfo(resultType, argTypes, required);
226}
227
228/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
229/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
230/// indicates that there is no meaningful 'this' type, and a null `md` can occur
231/// when calling a method pointer.
233 const CXXMethodDecl *md) {
234 CanQualType recTy;
235 if (rd) {
237 } else {
238 // This can happen with the MS ABI. It shouldn't need anything more than
239 // setting recTy to VoidTy here, but we're flagging it for now because we
240 // don't have the full handling implemented.
241 cgm.errorNYI("deriveThisType: no record decl");
242 recTy = getASTContext().VoidTy;
243 }
244
245 if (md)
246 recTy = CanQualType::CreateUnsafe(getASTContext().getAddrSpaceQualType(
247 recTy, md->getMethodQualifiers().getAddressSpace()));
248 return getASTContext().getPointerType(recTy);
249}
250
251/// Arrange the CIR function layout for a value of the given function type, on
252/// top of any implicit parameters already stored.
253static const CIRGenFunctionInfo &
257 RequiredArgs required =
260 appendParameterTypes(cgt, prefix, fpt);
261 CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
262 return cgt.arrangeCIRFunctionInfo(resultType, prefix, required);
263}
264
266 const VarDecl *param,
267 SourceLocation loc) {
268 // StartFunction converted the ABI-lowered parameter(s) into a local alloca.
269 // We need to turn that into an r-value suitable for emitCall
270 Address local = getAddrOfLocalVar(param);
271
272 QualType type = param->getType();
273
274 if (type->getAsCXXRecordDecl()) {
275 cgm.errorNYI(param->getSourceRange(),
276 "emitDelegateCallArg: record argument");
277 return;
278 }
279
280 // GetAddrOfLocalVar returns a pointer-to-pointer for references, but the
281 // argument needs to be the original pointer.
282 if (type->isReferenceType()) {
283 args.add(
284 RValue::get(builder.createLoad(getLoc(param->getSourceRange()), local)),
285 type);
286 } else if (getLangOpts().ObjCAutoRefCount) {
287 cgm.errorNYI(param->getSourceRange(),
288 "emitDelegateCallArg: ObjCAutoRefCount");
289 // For the most part, we just need to load the alloca, except that aggregate
290 // r-values are actually pointers to temporaries.
291 } else {
292 args.add(convertTempToRValue(local, type, loc), type);
293 }
294
295 // Deactivate the cleanup for the callee-destructed param that was pushed.
297 if (type->isRecordType() &&
298 type->castAsRecordDecl()->isParamDestroyedInCallee() &&
299 param->needsDestruction(getContext())) {
300 cgm.errorNYI(param->getSourceRange(),
301 "emitDelegateCallArg: callee-destructed param");
302 }
303}
304
305static const CIRGenFunctionInfo &
307 const CallArgList &args,
308 const FunctionType *fnType) {
309
311
312 if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
313 if (proto->isVariadic())
314 required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);
315 if (proto->hasExtParameterInfos())
316 cgm.errorNYI("call to functions with extra parameter info");
319 cgm.errorNYI("call to function without a prototype");
320
322 for (const CallArg &arg : args)
323 argTypes.push_back(cgt.getASTContext().getCanonicalParamType(arg.ty));
324
326
328 return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);
329}
330
331/// Arrange a call to a C++ method, passing the given arguments.
332///
333/// extraPrefixArgs is the number of ABI-specific args passed after the `this`
334/// parameter.
335/// passProtoArgs indicates whether `args` has args for the parameters in the
336/// given CXXConstructorDecl.
338 const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind,
339 unsigned extraPrefixArgs, unsigned extraSuffixArgs, bool passProtoArgs) {
340
341 // FIXME: Kill copy.
343 for (const auto &arg : args)
344 argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
345
346 // +1 for implicit this, which should always be args[0]
347 unsigned totalPrefixArgs = 1 + extraPrefixArgs;
348
350 RequiredArgs required = passProtoArgs
352 fpt, totalPrefixArgs + extraSuffixArgs)
354
355 GlobalDecl gd(d, ctorKind);
356 if (theCXXABI.hasThisReturn(gd))
357 cgm.errorNYI(d->getSourceRange(),
358 "arrangeCXXConstructorCall: hasThisReturn");
359 if (theCXXABI.hasMostDerivedReturn(gd))
360 cgm.errorNYI(d->getSourceRange(),
361 "arrangeCXXConstructorCall: hasMostDerivedReturn");
362 CanQualType resultType = astContext.VoidTy;
363
366
367 return arrangeCIRFunctionInfo(resultType, argTypes, required);
368}
369
370/// Arrange a call to a C++ method, passing the given arguments.
371///
372/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
373/// does not count `this`.
375 const CallArgList &args, const FunctionProtoType *proto,
376 RequiredArgs required, unsigned numPrefixArgs) {
378 assert(numPrefixArgs + 1 <= args.size() &&
379 "Emitting a call with less args than the required prefix?");
380
381 // FIXME: Kill copy.
383 for (const CallArg &arg : args)
384 argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
385
388 proto->getReturnType()->getCanonicalTypeUnqualified(), argTypes,
389 required);
390}
391
392const CIRGenFunctionInfo &
394 const FunctionType *fnType) {
395 return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
396}
397
398/// Arrange the argument and result information for a declaration or definition
399/// of the given C++ non-static member function. The member function must be an
400/// ordinary function, i.e. not a constructor or destructor.
401const CIRGenFunctionInfo &
403 assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
404 assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
405
406 auto prototype =
409
410 if (md->isInstance()) {
411 // The abstract case is perfectly fine.
412 auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
413 return arrangeCXXMethodType(thisType, prototype.getTypePtr(), md);
414 }
415
416 return arrangeFreeFunctionType(prototype);
417}
418
419/// Arrange the argument and result information for a call to an unknown C++
420/// non-static member function of the given abstract type. (A null RD means we
421/// don't have any meaningful "this" argument type, so fall back to a generic
422/// pointer type). The member fucntion must be an ordinary function, i.e. not a
423/// constructor or destructor.
424const CIRGenFunctionInfo &
426 const FunctionProtoType *fpt,
427 const CXXMethodDecl *md) {
429
430 // Add the 'this' pointer.
431 argTypes.push_back(deriveThisType(rd, md));
432
434 return ::arrangeCIRFunctionInfo(
435 *this, argTypes,
437}
438
439/// Arrange the argument and result information for the declaration or
440/// definition of the given function.
441const CIRGenFunctionInfo &
443 if (const auto *md = dyn_cast<CXXMethodDecl>(fd))
444 if (md->isInstance())
446
448
449 assert(isa<FunctionType>(funcTy));
450 // TODO: setCUDAKernelCallingConvention
452
453 // When declaring a function without a prototype, always use a non-variadic
454 // type.
455 if (CanQual<FunctionNoProtoType> noProto =
456 funcTy.getAs<FunctionNoProtoType>()) {
459 return arrangeCIRFunctionInfo(noProto->getReturnType(), {},
461 }
462
464}
465
466static cir::CIRCallOpInterface
467emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
468 cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
469 cir::FuncOp directFuncOp,
470 const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
471 const mlir::NamedAttrList &attrs) {
472 CIRGenBuilderTy &builder = cgf.getBuilder();
473
475
476 if (isInvoke) {
477 // This call may throw and requires catch and/or cleanup handling.
478 // If this call does not appear within the `try` region of an existing
479 // TryOp, we must create a synthetic TryOp to contain the call. This
480 // happens when a call that may throw appears within a cleanup
481 // scope.
482
483 // In OG, we build the landing pad for this scope. In CIR, we emit a
484 // synthetic cir.try because this didn't come from code generating from a
485 // try/catch in C++.
486 assert(cgf.curLexScope && "expected scope");
487 cir::TryOp tryOp = cgf.curLexScope->getClosestTryParent();
488 if (!tryOp) {
489 cgf.cgm.errorNYI(
490 "emitCallLikeOp: call does not have an associated cir.try");
491 return {};
492 }
493
494 if (tryOp.getSynthetic()) {
495 cgf.cgm.errorNYI("emitCallLikeOp: tryOp synthetic");
496 return {};
497 }
498
499 cir::CallOp callOpWithExceptions;
500 if (indirectFuncTy) {
501 cgf.cgm.errorNYI("emitCallLikeOp: indirect function type");
502 return {};
503 }
504
505 callOpWithExceptions =
506 builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
507
509 return callOpWithExceptions;
510 }
511
512 assert(builder.getInsertionBlock() && "expected valid basic block");
513
514 cir::CallOp op;
515 if (indirectFuncTy) {
516 // TODO(cir): Set calling convention for indirect calls.
518 op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,
519 cirCallArgs, attrs);
520 } else {
521 op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs);
522 }
523
524 return op;
525}
526
527const CIRGenFunctionInfo &
531 return ::arrangeCIRFunctionInfo(*this, argTypes, fpt);
532}
533
534const CIRGenFunctionInfo &
540
542 const CIRGenCallee &callee,
544 const CallArgList &args,
545 cir::CIRCallOpInterface *callOp,
546 mlir::Location loc) {
547 QualType retTy = funcInfo.getReturnType();
548 cir::FuncType cirFuncTy = getTypes().getFunctionType(funcInfo);
549
550 SmallVector<mlir::Value, 16> cirCallArgs(args.size());
551
553
554 // Translate all of the arguments as necessary to match the CIR lowering.
555 for (auto [argNo, arg, canQualArgType] :
556 llvm::enumerate(args, funcInfo.argTypes())) {
557
558 // Insert a padding argument to ensure proper alignment.
560
561 mlir::Type argType = convertType(canQualArgType);
562 if (!mlir::isa<cir::RecordType>(argType) &&
563 !mlir::isa<cir::ComplexType>(argType)) {
564 mlir::Value v;
565 if (arg.isAggregate())
566 cgm.errorNYI(loc, "emitCall: aggregate call argument");
567 v = arg.getKnownRValue().getValue();
568
569 // We might have to widen integers, but we should never truncate.
570 if (argType != v.getType() && mlir::isa<cir::IntType>(v.getType()))
571 cgm.errorNYI(loc, "emitCall: widening integer call argument");
572
573 // If the argument doesn't match, perform a bitcast to coerce it. This
574 // can happen due to trivial type mismatches.
575 // TODO(cir): When getFunctionType is added, assert that this isn't
576 // needed.
578 cirCallArgs[argNo] = v;
579 } else {
581 if (!arg.isAggregate()) {
582 src = createMemTemp(arg.ty, loc, "coerce");
583 arg.copyInto(*this, src, loc);
584 } else {
585 src = arg.hasLValue() ? arg.getKnownLValue().getAddress()
586 : arg.getKnownRValue().getAggregateAddress();
587 }
588
589 // Fast-isel and the optimizer generally like scalar values better than
590 // FCAs, so we flatten them if this is safe to do for this argument.
591 mlir::Type srcTy = src.getElementType();
592 // FIXME(cir): get proper location for each argument.
593 mlir::Location argLoc = loc;
594
595 // If the source type is smaller than the destination type of the
596 // coerce-to logic, copy the source value into a temp alloca the size
597 // of the destination type to allow loading all of it. The bits past
598 // the source value are left undef.
599 // FIXME(cir): add data layout info and compare sizes instead of
600 // matching the types.
601 //
602 // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
603 // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
604 // if (SrcSize < DstSize) {
606 if (srcTy != argType) {
607 cgm.errorNYI(loc, "emitCall: source type does not match argument type");
608 } else {
609 // FIXME(cir): this currently only runs when the types are exactly the
610 // same, but should be when alloc sizes are the same, fix this as soon
611 // as datalayout gets introduced.
613 }
614
615 // assert(NumCIRArgs == STy.getMembers().size());
616 // In LLVMGen: Still only pass the struct without any gaps but mark it
617 // as such somehow.
618 //
619 // In CIRGen: Emit a load from the "whole" struct,
620 // which shall be broken later by some lowering step into multiple
621 // loads.
623 cirCallArgs[argNo] = builder.createLoad(argLoc, src);
624 }
625 }
626
627 const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);
628 mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
629
631
632 mlir::NamedAttrList attrs;
633 StringRef funcName;
634 if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
635 funcName = calleeFuncOp.getName();
636
639 cir::CallingConv callingConv;
640 cir::SideEffect sideEffect;
641 cgm.constructAttributeList(funcName, funcInfo, callee.getAbstractInfo(),
642 attrs, callingConv, sideEffect,
643 /*attrOnCallSite=*/true, /*isThunk=*/false);
644
645 cir::FuncType indirectFuncTy;
646 mlir::Value indirectFuncVal;
647 cir::FuncOp directFuncOp;
648 if (auto fnOp = dyn_cast<cir::FuncOp>(calleePtr)) {
649 directFuncOp = fnOp;
650 } else if (auto getGlobalOp = mlir::dyn_cast<cir::GetGlobalOp>(calleePtr)) {
651 // FIXME(cir): This peephole optimization avoids indirect calls for
652 // builtins. This should be fixed in the builtin declaration instead by
653 // not emitting an unecessary get_global in the first place.
654 // However, this is also used for no-prototype functions.
655 mlir::Operation *globalOp = cgm.getGlobalValue(getGlobalOp.getName());
656 assert(globalOp && "undefined global function");
657 directFuncOp = mlir::cast<cir::FuncOp>(globalOp);
658 } else {
659 [[maybe_unused]] mlir::ValueTypeRange<mlir::ResultRange> resultTypes =
660 calleePtr->getResultTypes();
661 [[maybe_unused]] auto funcPtrTy =
662 mlir::dyn_cast<cir::PointerType>(resultTypes.front());
663 assert(funcPtrTy && mlir::isa<cir::FuncType>(funcPtrTy.getPointee()) &&
664 "expected pointer to function");
665
666 indirectFuncTy = cirFuncTy;
667 indirectFuncVal = calleePtr->getResult(0);
668 }
669
673
674 bool cannotThrow = attrs.getNamed("nothrow").has_value();
675 bool isInvoke = !cannotThrow && isCatchOrCleanupRequired();
676
677 mlir::Location callLoc = loc;
678 cir::CIRCallOpInterface theCall =
679 emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
680 cirCallArgs, isInvoke, attrs);
681
682 if (callOp)
683 *callOp = theCall;
684
687
688 mlir::Type retCIRTy = convertType(retTy);
689 if (isa<cir::VoidType>(retCIRTy))
690 return getUndefRValue(retTy);
691 switch (getEvaluationKind(retTy)) {
692 case cir::TEK_Aggregate: {
693 Address destPtr = returnValue.getValue();
694
695 if (!destPtr.isValid())
696 destPtr = createMemTemp(retTy, callLoc, getCounterAggTmpAsString());
697
698 mlir::ResultRange results = theCall->getOpResults();
699 assert(results.size() <= 1 && "multiple returns from a call");
700
701 SourceLocRAIIObject loc{*this, callLoc};
702 emitAggregateStore(results[0], destPtr);
703 return RValue::getAggregate(destPtr);
704 }
705 case cir::TEK_Scalar: {
706 mlir::ResultRange results = theCall->getOpResults();
707 assert(results.size() == 1 && "unexpected number of returns");
708
709 // If the argument doesn't match, perform a bitcast to coerce it. This
710 // can happen due to trivial type mismatches.
711 if (results[0].getType() != retCIRTy)
712 cgm.errorNYI(loc, "bitcast on function return value");
713
714 mlir::Region *region = builder.getBlock()->getParent();
715 if (region != theCall->getParentRegion())
716 cgm.errorNYI(loc, "function calls with cleanup");
717
718 return RValue::get(results[0]);
719 }
720 case cir::TEK_Complex: {
721 mlir::ResultRange results = theCall->getOpResults();
722 assert(!results.empty() &&
723 "Expected at least one result for complex rvalue");
724 return RValue::getComplex(results[0]);
725 }
726 }
727 llvm_unreachable("Invalid evaluation kind");
728}
729
731 mlir::Location loc) const {
732 LValue dst = cgf.makeAddrLValue(addr, ty);
733 if (!hasLV && rv.isScalar())
734 cgf.cgm.errorNYI(loc, "copyInto scalar value");
735 else if (!hasLV && rv.isComplex())
736 cgf.emitStoreOfComplex(loc, rv.getComplexValue(), dst, /*isInit=*/true);
737 else
738 cgf.cgm.errorNYI(loc, "copyInto hasLV");
739 isUsed = true;
740}
741
742mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc,
743 cir::FuncOp callee,
745 // TODO(cir): set the calling convention to this runtime call.
747
748 cir::CallOp call = builder.createCallOp(loc, callee, args);
749 assert(call->getNumResults() <= 1 &&
750 "runtime functions have at most 1 result");
751
752 if (call->getNumResults() == 0)
753 return nullptr;
754
755 return call->getResult(0);
756}
757
759 clang::QualType argType) {
760 assert(argType->isReferenceType() == e->isGLValue() &&
761 "reference binding to unmaterialized r-value!");
762
763 if (e->isGLValue()) {
764 assert(e->getObjectKind() == OK_Ordinary);
765 return args.add(emitReferenceBindingToExpr(e), argType);
766 }
767
768 bool hasAggregateEvalKind = hasAggregateEvaluationKind(argType);
769
770 // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
771 // However, we still have to push an EH-only cleanup in case we unwind before
772 // we make it to the call.
773 if (argType->isRecordType() &&
776 cgm.errorNYI(e->getSourceRange(), "emitCallArg: msabi is NYI");
777 }
778
779 if (hasAggregateEvalKind && isa<ImplicitCastExpr>(e) &&
780 cast<CastExpr>(e)->getCastKind() == CK_LValueToRValue) {
781 LValue lv = emitLValue(cast<CastExpr>(e)->getSubExpr());
782 assert(lv.isSimple());
783 args.addUncopiedAggregate(lv, argType);
784 return;
785 }
786
787 args.add(emitAnyExprToTemp(e), argType);
788}
789
790QualType CIRGenFunction::getVarArgType(const Expr *arg) {
791 // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
792 // implicitly widens null pointer constants that are arguments to varargs
793 // functions to pointer-sized ints.
794 if (!getTarget().getTriple().isOSWindows())
795 return arg->getType();
796
798 cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");
799 return arg->getType();
800}
801
802/// Similar to emitAnyExpr(), however, the result will always be accessible
803/// even if no aggregate location is provided.
806
808 aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()),
810
811 return emitAnyExpr(e, aggSlot);
812}
813
815 CallArgList &args, PrototypeWrapper prototype,
816 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
817 AbstractCallee callee, unsigned paramsToSkip) {
819
821
822 // First, if a prototype was provided, use those argument types.
823 bool isVariadic = false;
824 if (prototype.p) {
826
827 const auto *fpt = cast<const FunctionProtoType *>(prototype.p);
828 isVariadic = fpt->isVariadic();
830 argTypes.assign(fpt->param_type_begin() + paramsToSkip,
831 fpt->param_type_end());
832 }
833
834 // If we still have any arguments, emit them using the type of the argument.
835 for (const clang::Expr *a : llvm::drop_begin(argRange, argTypes.size()))
836 argTypes.push_back(isVariadic ? getVarArgType(a) : a->getType());
837 assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));
838
839 // We must evaluate arguments from right to left in the MS C++ ABI, because
840 // arguments are destroyed left to right in the callee. As a special case,
841 // there are certain language constructs taht require left-to-right
842 // evaluation, and in those cases we consider the evaluation order requirement
843 // to trump the "destruction order is reverse construction order" guarantee.
844 auto leftToRight = true;
846
847 auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,
848 RValue emittedArg) {
849 if (!callee.hasFunctionDecl() || i >= callee.getNumParams())
850 return;
851 auto *ps = callee.getParamDecl(i)->getAttr<PassObjectSizeAttr>();
852 if (!ps)
853 return;
854
856 cgm.errorNYI("emit implicit object size for call arg");
857 };
858
859 // Evaluate each argument in the appropriate order.
860 size_t callArgsStart = args.size();
861 for (size_t i = 0; i != argTypes.size(); ++i) {
862 size_t idx = leftToRight ? i : argTypes.size() - i - 1;
863 CallExpr::const_arg_iterator currentArg = argRange.begin() + idx;
864 size_t initialArgSize = args.size();
865
866 emitCallArg(args, *currentArg, argTypes[idx]);
867
868 // In particular, we depend on it being the last arg in Args, and the
869 // objectsize bits depend on there only being one arg if !LeftToRight.
870 assert(initialArgSize + 1 == args.size() &&
871 "The code below depends on only adding one arg per emitCallArg");
872 (void)initialArgSize;
873
874 // Since pointer argument are never emitted as LValue, it is safe to emit
875 // non-null argument check for r-value only.
876 if (!args.back().hasLValue()) {
877 RValue rvArg = args.back().getKnownRValue();
879 maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);
880 }
881
882 if (!leftToRight)
883 std::reverse(args.begin() + callArgsStart, args.end());
884 }
885}
static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, cir::FuncOp directFuncOp, const SmallVectorImpl< mlir::Value > &cirCallArgs, bool isInvoke, const mlir::NamedAttrList &attrs)
static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl< CanQualType > &prefix, CanQual< FunctionProtoType > fpt)
Arrange the CIR function layout for a value of the given function type, on top of any implicit parame...
static void appendParameterTypes(const CIRGenTypes &cgt, SmallVectorImpl< CanQualType > &prefix, CanQual< FunctionProtoType > fpt)
Adds the formal parameters in FPT to the given prefix.
static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder, mlir::NamedAttrList &attrs, const FunctionProtoType *fpt)
static CanQual< FunctionProtoType > getFormalType(const CXXMethodDecl *md)
Returns the canonical formal type of the given C++ method.
static const CIRGenFunctionInfo & arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, const CallArgList &args, const FunctionType *fnType)
TokenType getType() const
Returns the token's type, e.g.
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={})
cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={})
CanQualType getCanonicalParamType(QualType T) const
Return the canonical parameter type corresponding to the specific potentially non-canonical one.
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType VoidTy
CanQualType getCanonicalTagType(const TagDecl *TD) const
mlir::Type getElementType() const
Definition Address.h:122
static Address invalid()
Definition Address.h:73
bool isValid() const
Definition Address.h:74
An aggregate value slot.
static AggValueSlot ignored()
Returns an aggregate value slot indicating that the aggregate value is being ignored.
virtual CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty, SourceLocation loc)=0
Build a virtual function pointer in the ABI-specific way.
Abstract information about a function or function prototype.
Definition CIRGenCall.h:27
clang::GlobalDecl getCalleeDecl() const
Definition CIRGenCall.h:44
const clang::FunctionProtoType * getCalleeFunctionProtoType() const
Definition CIRGenCall.h:41
CIRGenCalleeInfo getAbstractInfo() const
Definition CIRGenCall.h:140
clang::GlobalDecl getVirtualMethodDecl() const
Definition CIRGenCall.h:170
CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const
If this is a delayed callee computation of some sort, prepare a concrete callee.
Address getThisAddress() const
Definition CIRGenCall.h:175
cir::FuncType getVirtualFunctionType() const
Definition CIRGenCall.h:180
const clang::CallExpr * getVirtualCallExpr() const
Definition CIRGenCall.h:165
mlir::Operation * getFunctionPointer() const
Definition CIRGenCall.h:147
llvm::MutableArrayRef< CanQualType > argTypes()
llvm::ArrayRef< CanQualType > requiredArguments() const
const_arg_iterator argTypesBegin() const
static CIRGenFunctionInfo * create(CanQualType resultType, llvm::ArrayRef< CanQualType > argTypes, RequiredArgs required)
An abstract representation of regular/ObjC call/message targets.
const clang::ParmVarDecl * getParamDecl(unsigned I) const
void emitCallArgs(CallArgList &args, PrototypeWrapper prototype, llvm::iterator_range< clang::CallExpr::const_arg_iterator > argRange, AbstractCallee callee=AbstractCallee(), unsigned paramsToSkip=0)
mlir::Type convertType(clang::QualType t)
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
RValue convertTempToRValue(Address addr, clang::QualType type, clang::SourceLocation loc)
Given the address of a temporary variable, produce an r-value of its type.
CIRGenTypes & getTypes() const
const clang::LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
Address getAddrOfLocalVar(const clang::VarDecl *vd)
Return the address of a local variable.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAggregateStore(mlir::Value value, Address dest)
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
AggValueSlot createAggTemp(QualType ty, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr)
Create a temporary memory object for the given aggregate type.
void populateCatchHandlersIfRequired(cir::TryOp tryOp)
RValue getUndefRValue(clang::QualType ty)
Get an appropriate 'undef' rvalue for the given type.
Address returnValue
The temporary alloca to hold the return value.
static bool hasAggregateEvaluationKind(clang::QualType type)
RValue emitAnyExprToTemp(const clang::Expr *e)
Similarly to emitAnyExpr(), however, the result will always be accessible even if no aggregate locati...
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, mlir::Location loc)
void emitCallArg(CallArgList &args, const clang::Expr *e, clang::QualType argType)
CIRGenBuilderTy & getBuilder()
mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, llvm::ArrayRef< mlir::Value > args={})
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
RValue emitAnyExpr(const clang::Expr *e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
Emit code to compute the specified expression which can have any type.
void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param, clang::SourceLocation loc)
We are performing a delegate call; that is, the current function is delegating to another one.
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
clang::ASTContext & getContext() const
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
CIRGenBuilderTy & getBuilder()
const TargetCIRGenInfo & getTargetCIRGenInfo()
mlir::MLIRContext & getMLIRContext()
CIRGenCXXABI & getCXXABI() const
void constructAttributeList(llvm::StringRef name, const CIRGenFunctionInfo &info, CIRGenCalleeInfo calleeInfo, mlir::NamedAttrList &attrs, cir::CallingConv &callingConv, cir::SideEffect &sideEffect, bool attrOnCallSite, bool isThunk)
Get the CIR attributes and calling convention to use for a particular function type.
This class organizes the cross-module state that is used while lowering AST types to CIR types.
Definition CIRGenTypes.h:48
CIRGenModule & getCGModule() const
Definition CIRGenTypes.h:82
const CIRGenFunctionInfo & arrangeGlobalDeclaration(GlobalDecl gd)
const CIRGenFunctionInfo & arrangeCXXMethodDeclaration(const clang::CXXMethodDecl *md)
C++ methods have some special rules and also have implicit parameters.
const CIRGenFunctionInfo & arrangeCXXStructorDeclaration(clang::GlobalDecl gd)
const CIRGenFunctionInfo & arrangeFreeFunctionCall(const CallArgList &args, const FunctionType *fnType)
const CIRGenFunctionInfo & arrangeFreeFunctionType(CanQual< FunctionProtoType > fpt)
bool isFuncTypeConvertible(const clang::FunctionType *ft)
Utility to check whether a function type can be converted to a CIR type (i.e.
cir::FuncType getFunctionTypeForVTable(clang::GlobalDecl gd)
Get the CIR function type for use in a vtable, given a CXXMethodDecl.
const CIRGenFunctionInfo & arrangeCXXConstructorCall(const CallArgList &args, const clang::CXXConstructorDecl *d, clang::CXXCtorType ctorKind, unsigned extraPrefixArgs, unsigned extraSuffixArgs, bool passProtoArgs=true)
Arrange a call to a C++ method, passing the given arguments.
const CIRGenFunctionInfo & arrangeCXXMethodType(const clang::CXXRecordDecl *rd, const clang::FunctionProtoType *ftp, const clang::CXXMethodDecl *md)
Arrange the argument and result information for a call to an unknown C++ non-static member function o...
const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CanQualType returnType, llvm::ArrayRef< CanQualType > argTypes, RequiredArgs required)
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
clang::CanQualType deriveThisType(const clang::CXXRecordDecl *rd, const clang::CXXMethodDecl *md)
Derives the 'this' type for CIRGen purposes, i.e.
const CIRGenFunctionInfo & arrangeFunctionDeclaration(const clang::FunctionDecl *fd)
Free functions are functions that are compatible with an ordinary C function pointer type.
clang::ASTContext & getASTContext() const
const CIRGenFunctionInfo & arrangeCXXMethodCall(const CallArgList &args, const clang::FunctionProtoType *type, RequiredArgs required, unsigned numPrefixArgs)
Arrange a call to a C++ method, passing the given arguments.
mlir::Type convertType(clang::QualType type)
Convert a Clang type into a mlir::Type.
void addUncopiedAggregate(LValue lvalue, clang::QualType type)
Definition CIRGenCall.h:237
void add(RValue rvalue, clang::QualType type)
Definition CIRGenCall.h:235
bool isSimple() const
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
static RValue getAggregate(Address addr, bool isVolatile=false)
Convert an Address to an RValue.
static RValue getComplex(mlir::Value v)
Definition CIRGenValue.h:91
A class for recording the number of arguments that a function signature requires.
static RequiredArgs getFromProtoWithExtraSlots(const clang::FunctionProtoType *prototype, unsigned additional)
Compute the arguments required by the given formal prototype, given that there may be some additional...
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition CIRGenCall.h:256
virtual bool isNoProtoCallVariadic(const FunctionNoProtoType *fnType) const
Determine whether a call to an unprototyped functions under the given calling convention should use t...
Represents a C++ constructor within a class.
Definition DeclCXX.h:2604
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
bool isInstance() const
Definition DeclCXX.h:2156
Qualifiers getMethodQualifiers() const
Definition DeclCXX.h:2290
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2943
SourceLocation getBeginLoc() const
Definition Expr.h:3277
ConstExprIterator const_arg_iterator
Definition Expr.h:3191
Represents a canonical, potentially-qualified type.
static CanQual< Type > CreateUnsafe(QualType Other)
CanProxy< U > castAs() const
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
CanProxy< U > getAs() const
Retrieve a canonical type pointer with a different static type, upcasting or downcasting as needed.
T * getAttr() const
Definition DeclBase.h:573
bool hasAttr() const
Definition DeclBase.h:577
This represents one expression.
Definition Expr.h:112
bool isGLValue() const
Definition Expr.h:287
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition Expr.h:451
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2000
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4549
Represents a K&R-style 'int foo()' function, which has no information available about its arguments.
Definition TypeBase.h:4847
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5269
ExceptionSpecificationType getExceptionSpecType() const
Get the kind of exception specification on this function.
Definition TypeBase.h:5576
bool isNothrow(bool ResultIfDependent=false) const
Determine whether this function type has a non-throwing exception specification.
Definition TypeBase.h:5668
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4465
QualType getReturnType() const
Definition TypeBase.h:4805
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
const Decl * getDecl() const
Definition GlobalDecl.h:106
A (possibly-)qualified type.
Definition TypeBase.h:937
LangAS getAddressSpace() const
Definition TypeBase.h:571
bool isParamDestroyedInCallee() const
Definition Decl.h:4474
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
CanQualType getCanonicalTypeUnqualified() const
bool isReferenceType() const
Definition TypeBase.h:8553
RecordDecl * castAsRecordDecl() const
Definition Type.h:48
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9111
bool isRecordType() const
Definition TypeBase.h:8656
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2201
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2862
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
CXXCtorType
C++ constructor types.
Definition ABI.h:24
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:151
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool opCallBitcastArg()
static bool opCallCIRGenFuncInfoExtParamInfo()
static bool functionUsesSEHTry()
static bool emitLifetimeMarkers()
static bool lowerAggregateLoadStore()
static bool opCallSurroundingTry()
static bool nothrowAttr()
static bool opCallReturn()
static bool opCallPaddingArgs()
static bool opCallExtParameterInfo()
static bool dataLayoutTypeAllocSize()
static bool opCallObjCMethod()
static bool opCallInAlloca()
static bool opCallCallConv()
static bool opFuncCallingConv()
static bool opCallAttrs()
static bool opCallImplicitObjectSizeArgs()
static bool opCallMustTail()
static bool cudaSupport()
static bool opCallFnInfoOpts()
static bool msvcCXXPersonality()
static bool opCallCIRGenFuncInfoParamInfo()
Similar to AddedStructorArgs, but only notes the number of additional arguments.
llvm::PointerUnion< const clang::FunctionProtoType *, const clang::ObjCMethodDecl * > p
clang::QualType ty
Definition CIRGenCall.h:208
void copyInto(CIRGenFunction &cgf, Address addr, mlir::Location loc) const