clang 24.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"
18#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
19#include "mlir/IR/Attributes.h"
22#include "llvm/ADT/FloatingPointMode.h"
23#include "llvm/ADT/StringSet.h"
24#include "llvm/Support/TypeSize.h"
25
26using namespace clang;
27using namespace clang::CIRGen;
28
29CIRGenFunctionInfo *CIRGenFunctionInfo::create(
32 // The first slot allocated for arg type slot is for the return value.
33 void *buffer = operator new(
34 totalSizeToAlloc<CanQualType>(argTypes.size() + 1));
35
37
38 CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();
39
40 fi->noReturn = info.getNoReturn();
41 fi->instanceMethod = isInstanceMethod;
42
43 fi->required = required;
44 fi->numArgs = argTypes.size();
45
46 // requiredArguments() reads getNumRequiredArgs() entries out of the
47 // trailing-object array, so a signature that claims more required arguments
48 // than we have types for reads past the end and hands a null QualType to
49 // convertType.
50 assert((!required.allowsOptionalArgs() ||
51 required.getNumRequiredArgs() <= fi->numArgs) &&
52 "more required arguments than argument types");
53
54 fi->getArgTypes()[0] = resultType;
55 std::copy(argTypes.begin(), argTypes.end(), fi->argTypesBegin());
57
58 return fi;
59}
60
65
67 mlir::Type resultType = convertType(info.getReturnType());
69 argTypes.reserve(info.getNumRequiredArgs());
70
71 for (const CanQualType &argType : info.requiredArguments())
72 argTypes.push_back(convertType(argType));
73
74 return cir::FuncType::get(argTypes,
75 (resultType ? resultType : builder.getVoidTy()),
76 info.isVariadic());
77}
78
80 if (isVirtual()) {
81 const CallExpr *ce = getVirtualCallExpr();
84 ce ? ce->getBeginLoc() : SourceLocation());
85 }
86 return *this;
87}
88
89void CIRGenFunction::emitAggregateStore(mlir::Value value, Address dest) {
90 // In classic codegen:
91 // Function to store a first-class aggregate into memory. We prefer to
92 // store the elements rather than the aggregate to be more friendly to
93 // fast-isel.
94 // In CIR codegen:
95 // Emit the most simple cir.store possible (e.g. a store for a whole
96 // record), which can later be broken down in other CIR levels (or prior
97 // to dialect codegen).
98
99 // Stored result for the callers of this function expected to be in the same
100 // scope as the value, don't make assumptions about current insertion point.
101 mlir::OpBuilder::InsertionGuard guard(builder);
102 builder.setInsertionPointAfter(value.getDefiningOp());
103 builder.createStore(*currSrcLoc, value, dest);
104}
105
107 mlir::NamedAttrList &attrs,
108 const FunctionProtoType *fpt) {
109 if (!fpt)
110 return;
111
113 fpt->isNothrow())
114 attrs.set(cir::CIRDialect::getNoThrowAttrName(),
115 mlir::UnitAttr::get(builder.getContext()));
116}
117
118static void addNoBuiltinAttributes(mlir::MLIRContext &ctx,
119 mlir::NamedAttrList &attrs,
120 const LangOptions &langOpts,
121 const NoBuiltinAttr *nba = nullptr) {
122 // First, handle the language options passed through -fno-builtin.
123 // or, if there is a wildcard in the builtin names specified through the
124 // attribute, disable them all.
125 if (langOpts.NoBuiltin ||
126 (nba && llvm::is_contained(nba->builtinNames(), "*"))) {
127 // -fno-builtin disables them all.
128 // Empty attribute means 'all'.
129 attrs.set(cir::CIRDialect::getNoBuiltinsAttrName(),
130 mlir::ArrayAttr::get(&ctx, {}));
131 return;
132 }
133
134 llvm::SetVector<mlir::Attribute> nbFuncs;
135 auto addNoBuiltinAttr = [&ctx, &nbFuncs](StringRef builtinName) {
136 nbFuncs.insert(mlir::StringAttr::get(&ctx, builtinName));
137 };
138
139 // Then, add attributes for builtins specified through -fno-builtin-<name>.
140 llvm::for_each(langOpts.NoBuiltinFuncs, addNoBuiltinAttr);
141
142 // Now, let's check the __attribute__((no_builtin("...")) attribute added to
143 // the source.
144 if (nba)
145 llvm::for_each(nba->builtinNames(), addNoBuiltinAttr);
146
147 if (!nbFuncs.empty())
148 attrs.set(cir::CIRDialect::getNoBuiltinsAttrName(),
149 mlir::ArrayAttr::get(&ctx, nbFuncs.getArrayRef()));
150}
151
152/// Add denormal-fp-math and denormal-fp-math-f32 as appropriate for the
153/// requested denormal behavior, accounting for the overriding behavior of the
154/// -f32 case.
155static void addDenormalModeAttrs(llvm::DenormalMode fpDenormalMode,
156 llvm::DenormalMode fp32DenormalMode,
157 mlir::NamedAttrList &attrs) {
158 // TODO(cir): Classic-codegen sets the denormal modes here. There are two
159 // values, both with a string, but it seems that perhaps we could combine
160 // these into a single attribute? It seems a little silly to have two so
161 // similar named attributes that do the same thing.
162}
163
164/// Add default attributes to a function, which have merge semantics under
165/// -mlink-builtin-bitcode and should not simply overwrite any existing
166/// attributes in the linked library.
167static void
169 mlir::NamedAttrList &attrs) {
171 attrs);
172}
173
174static llvm::StringLiteral
175getZeroCallUsedRegsKindStr(llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind k) {
176 switch (k) {
177 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip:
178 llvm_unreachable("No string value, shouldn't be able to get here");
179 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedGPRArg:
180 return "used-gpr-arg";
181 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedGPR:
182 return "used-gpr";
183 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedArg:
184 return "used-arg";
185 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Used:
186 return "used";
187 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllGPRArg:
188 return "all-gpr-arg";
189 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllGPR:
190 return "all-gpr";
191 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllArg:
192 return "all-arg";
193 case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::All:
194 return "all";
195 }
196
197 llvm_unreachable("Unknown kind?");
198}
199
200/// Add default attributes to a function, which have merge semantics under
201/// -mlink-builtin-bitcode and should not simply overwrite any existing
202/// attributes in the linked library.
204 mlir::MLIRContext *mlirCtx, StringRef name, bool hasOptNoneAttr,
205 const CodeGenOptions &codeGenOpts, const LangOptions &langOpts,
206 bool attrOnCallSite, mlir::NamedAttrList &attrs) {
207 // TODO(cir): Handle optimize attribute flag here.
208 // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
209 if (!hasOptNoneAttr) {
210 if (codeGenOpts.OptimizeSize)
211 attrs.set(cir::CIRDialect::getOptimizeForSizeAttrName(),
212 mlir::UnitAttr::get(mlirCtx));
213 if (codeGenOpts.OptimizeSize == 2)
214 attrs.set(cir::CIRDialect::getMinSizeAttrName(),
215 mlir::UnitAttr::get(mlirCtx));
216 }
217
218 // TODO(cir): Classic codegen adds 'DisableRedZone', 'indirect-tls-seg-refs'
219 // and 'NoImplicitFloat' here.
220
221 if (attrOnCallSite) {
222 // Add the 'nobuiltin' tag, which is different from 'no-builtins'.
223 if (!codeGenOpts.SimplifyLibCalls || langOpts.isNoBuiltinFunc(name))
224 attrs.set(cir::CIRDialect::getNoBuiltinAttrName(),
225 mlir::UnitAttr::get(mlirCtx));
226
227 if (!codeGenOpts.TrapFuncName.empty())
228 attrs.set(cir::CIRDialect::getTrapFuncNameAttrName(),
229 mlir::StringAttr::get(mlirCtx, codeGenOpts.TrapFuncName));
230 } else {
231 // TODO(cir): Set frame pointer attribute here.
232 // TODO(cir): a number of other attribute 1-offs based on codegen/lang opts
233 // should be done here: less-recise-fpmad null-pointer-is-valid
234 // no-trapping-math
235 // various inf/nan/nsz/etc work here.
236 //
237 // TODO(cir): set stack-protector buffer size attribute (sorted oddly in
238 // classic compiler inside of the above region, but should be done on its
239 // own).
240 // TODO(cir): other attributes here:
241 // reciprocal estimates, prefer-vector-width, stackrealign, backchain,
242 // split-stack, speculative-load-hardening.
243
244 if (codeGenOpts.getZeroCallUsedRegs() ==
245 llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip)
246 attrs.erase(cir::CIRDialect::getZeroCallUsedRegsAttrName());
247 else
248 attrs.set(cir::CIRDialect::getZeroCallUsedRegsAttrName(),
249 mlir::StringAttr::get(mlirCtx,
251 codeGenOpts.getZeroCallUsedRegs())));
252 }
253
254 if (langOpts.assumeFunctionsAreConvergent()) {
255 // Conservatively, mark all functions and calls in CUDA and OpenCL as
256 // convergent (meaning, they may call an intrinsically convergent op, such
257 // as __syncthreads() / barrier(), and so can't have certain optimizations
258 // applied around them). LLVM will remove this attribute where it safely
259 // can.
260 attrs.set(cir::CIRDialect::getConvergentAttrName(),
261 mlir::UnitAttr::get(mlirCtx));
262 }
263
264 // TODO(cir): Classic codegen adds 'nounwind' here in a bunch of offload
265 // targets.
266
267 if (codeGenOpts.SaveRegParams && !attrOnCallSite)
268 attrs.set(cir::CIRDialect::getSaveRegParamsAttrName(),
269 mlir::UnitAttr::get(mlirCtx));
270
271 // These come in the form of an optional equality sign, so make sure we pass
272 // these on correctly. These will eventually just be passed through to
273 // LLVM-IR, but we want to put them all in 1 array to simplify the
274 // LLVM-MLIR dialect.
275 SmallVector<mlir::NamedAttribute> defaultFuncAttrs;
276 llvm::transform(
277 codeGenOpts.DefaultFunctionAttrs, std::back_inserter(defaultFuncAttrs),
278 [mlirCtx](llvm::StringRef arg) {
279 auto [var, value] = arg.split('=');
280 auto valueAttr =
281 value.empty()
282 ? cast<mlir::Attribute>(mlir::UnitAttr::get(mlirCtx))
283 : cast<mlir::Attribute>(mlir::StringAttr::get(mlirCtx, value));
284 return mlir::NamedAttribute(var, valueAttr);
285 });
286
287 if (!defaultFuncAttrs.empty())
288 attrs.set(cir::CIRDialect::getDefaultFuncAttrsAttrName(),
289 mlir::DictionaryAttr::get(mlirCtx, defaultFuncAttrs));
290
291 // TODO(cir): Do branch protection attributes here.
292}
293
294/// This function matches the behavior of 'getDefaultFunctionAttributes' from
295/// classic codegen, despite the similarity of its name to
296/// 'addDefaultFunctionDefinitionAttributes', which is a caller of this
297/// function.
299 bool hasOptNoneAttr,
300 bool attrOnCallSite,
301 mlir::NamedAttrList &attrs) {
302
304 codeGenOpts, langOpts, attrOnCallSite,
305 attrs);
306
307 if (!attrOnCallSite) {
308 // TODO(cir): Classic codegen adds pointer-auth attributes here, by calling
309 // into TargetCodeGenInfo. At the moment, we've not looked into this as it
310 // is somewhat less used.
311 addMergeableDefaultFunctionAttributes(codeGenOpts, attrs);
312 }
313}
314
315/// Construct the CIR attribute list of a function or call.
317 llvm::StringRef name, const CIRGenFunctionInfo &info,
318 CIRGenCalleeInfo calleeInfo, mlir::NamedAttrList &attrs,
320 mlir::NamedAttrList &retAttrs, cir::CallingConv &callingConv,
321 cir::SideEffect &sideEffect, bool attrOnCallSite, bool isThunk) {
323 sideEffect = cir::SideEffect::All;
324
325 auto addUnitAttr = [&](llvm::StringRef name) {
326 attrs.set(name, mlir::UnitAttr::get(&getMLIRContext()));
327 };
328
329 if (info.isNoReturn())
330 addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
331
332 // TODO(cir): Implement/check the CSME Nonsecure call attribute here. This
333 // requires being in CSME mode.
334
336 calleeInfo.getCalleeFunctionProtoType());
337
338 const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
339
340 // TODO(cir): OMP Assume Attributes should be here.
341
342 const NoBuiltinAttr *nba = nullptr;
343
344 // TODO(cir): Some work for arg memory effects can be done here, as it is in
345 // classic codegen.
346
347 if (targetDecl) {
348 if (targetDecl->hasAttr<NoThrowAttr>())
349 addUnitAttr(cir::CIRDialect::getNoThrowAttrName());
350 // TODO(cir): This is actually only possible if targetDecl isn't a
351 // declarator, which ObjCMethodDecl seems to be the only way to get this to
352 // happen. We're including it here for completeness, but we should add a
353 // test for this when we start generating ObjectiveC.
354 if (targetDecl->hasAttr<NoReturnAttr>())
355 addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
356 if (targetDecl->hasAttr<ReturnsTwiceAttr>())
357 addUnitAttr(cir::CIRDialect::getReturnsTwiceAttrName());
358 if (targetDecl->hasAttr<ColdAttr>())
359 addUnitAttr(cir::CIRDialect::getColdAttrName());
360 if (targetDecl->hasAttr<HotAttr>())
361 addUnitAttr(cir::CIRDialect::getHotAttrName());
362 if (targetDecl->hasAttr<NoDuplicateAttr>())
363 addUnitAttr(cir::CIRDialect::getNoDuplicatesAttrName());
364 if (targetDecl->hasAttr<ConvergentAttr>())
365 addUnitAttr(cir::CIRDialect::getConvergentAttrName());
366
367 if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
369 getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
370
371 // TODO(cir): When doing 'return attrs' we need to cover the 'NoAlias' for
372 // global allocation functions here.
374
375 const CXXMethodDecl *md = dyn_cast<CXXMethodDecl>(func);
376 bool isVirtualCall = md && md->isVirtual();
377
378 // Don't use [[noreturn]], _Noreturn or [[no_builtin]] for a call to a
379 // virtual function. These attributes are not inherited by overloads.
380 if (!(attrOnCallSite && isVirtualCall)) {
381 if (func->isNoReturn())
382 addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
383 nba = func->getAttr<NoBuiltinAttr>();
384 }
385 }
386
388
389 // 'const', 'pure' and 'noalias' attributed functions are also nounwind.
390 if (targetDecl->hasAttr<ConstAttr>()) {
391 // gcc specifies that 'const' functions have greater restrictions than
392 // 'pure' functions, so they also cannot have infinite loops.
393 sideEffect = cir::SideEffect::Const;
394 } else if (targetDecl->hasAttr<PureAttr>()) {
395 // gcc specifies that 'pure' functions cannot have infinite loops.
396 sideEffect = cir::SideEffect::Pure;
397 }
398
399 attrs.set(cir::CIRDialect::getSideEffectAttrName(),
400 cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
401
402 // TODO(cir): Add noalias to returns for malloc-like functions
403 // (__attribute__((malloc)) / __declspec(restrict)).
404
405 if (targetDecl->hasAttr<ReturnsNonNullAttr>() &&
406 !codeGenOpts.NullPointerIsValid)
407 retAttrs.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
408 mlir::UnitAttr::get(&getMLIRContext()));
409 if (targetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
410 addUnitAttr(cir::CIRDialect::getNoCallerSavedRegsAttrName());
411 // TODO(cir): Implement 'NoCFCheck' attribute here. This requires
412 // fcf-protection mode.
413 if (targetDecl->hasAttr<LeafAttr>())
414 addUnitAttr(cir::CIRDialect::getNoCallbackAttrName());
415 // TODO(cir): Implement 'BPFFastCall' attribute here. This requires C, and
416 // the BPF target.
417
418 if (auto *allocSizeAttr = targetDecl->getAttr<AllocSizeAttr>()) {
419 unsigned size = allocSizeAttr->getElemSizeParam().getLLVMIndex();
420
421 if (allocSizeAttr->getNumElemsParam().isValid()) {
422 unsigned numElts = allocSizeAttr->getNumElemsParam().getLLVMIndex();
423 attrs.set(cir::CIRDialect::getAllocSizeAttrName(),
424 builder.getDenseI32ArrayAttr(
425 {static_cast<int>(size), static_cast<int>(numElts)}));
426 } else {
427 attrs.set(cir::CIRDialect::getAllocSizeAttrName(),
428 builder.getDenseI32ArrayAttr({static_cast<int>(size)}));
429 }
430 }
431
432 // TODO(cir): Quite a few CUDA and OpenCL attributes are added here, like
433 // uniform-work-group-size.
434
435 if (langOpts.CUDA && !langOpts.CUDAIsDevice &&
436 targetDecl->hasAttr<CUDAGlobalAttr>()) {
437 GlobalDecl kernel(calleeInfo.getCalleeDecl());
438 llvm::StringRef kernelName = getMangledName(
440 auto attr = cir::CUDAKernelNameAttr::get(
442 mlir::StringAttr::get(&getMLIRContext(), kernelName));
443 attrs.set(attr.getMnemonic(), attr);
444 }
445
446 // TODO(cir): we should also do 'aarch64_pstate_sm_body' here.
447
448 if (auto *modularFormat = targetDecl->getAttr<ModularFormatAttr>()) {
449 FormatAttr *format = targetDecl->getAttr<FormatAttr>();
450 StringRef type = format->getType()->getName();
451 std::string formatIdx = std::to_string(format->getFormatIdx());
452 std::string firstArg = std::to_string(format->getFirstArg());
454 type, formatIdx, firstArg,
455 modularFormat->getModularImplFn()->getName(),
456 modularFormat->getImplName()};
457 llvm::append_range(args, modularFormat->aspects());
458 attrs.set(cir::CIRDialect::getModularFormatAttrName(),
459 builder.getStringAttr(llvm::join(args, ",")));
460 }
461 }
462
464
465 bool hasOptNoneAttr = targetDecl && targetDecl->hasAttr<OptimizeNoneAttr>();
466 addDefaultFunctionAttributes(name, hasOptNoneAttr, attrOnCallSite, attrs);
467 if (targetDecl) {
468 // TODO(cir): There is another region of `if (targetDecl)` that handles
469 // removing some attributes that are necessary modifications of the
470 // default-function attrs. Including:
471 // NoSpeculativeLoadHardening
472 // SpeculativeLoadHardening
473 // NoSplitStack
474 // Non-lazy-bind
475 // 'sample-profile-suffix-elision-policy'.
476
477 if (targetDecl->hasAttr<ZeroCallUsedRegsAttr>()) {
478 // A function "__attribute__((...))" overrides the command-line flag.
479 auto kind =
480 targetDecl->getAttr<ZeroCallUsedRegsAttr>()->getZeroCallUsedRegs();
481 attrs.set(
482 cir::CIRDialect::getZeroCallUsedRegsAttrName(),
483 mlir::StringAttr::get(
485 ZeroCallUsedRegsAttr::ConvertZeroCallUsedRegsKindToStr(kind)));
486 }
487
488 if (targetDecl->hasAttr<NoConvergentAttr>())
489 attrs.erase(cir::CIRDialect::getConvergentAttrName());
490 }
491
492 // Collect non-call-site function IR attributes from declaration-specific
493 // information.
494 if (!attrOnCallSite) {
495 // These functions require the returns_twice attribute for correct
496 // codegen, but the attribute may not be added if -fno-builtin is
497 // specified. We explicitly add that attribute here.
498 static const llvm::StringSet<> returnsTwiceFn{
499 "_setjmpex", "setjmp", "_setjmp", "vfork",
500 "sigsetjmp", "__sigsetjmp", "savectx", "getcontext"};
501 if (returnsTwiceFn.contains(name))
502 addUnitAttr(cir::CIRDialect::getReturnsTwiceAttrName());
503
504 llvm::StringMap<std::string> cpuAndFeatures;
505 if (getCPUAndFeaturesAttributes(calleeInfo.getCalleeDecl(),
506 cpuAndFeatures)) {
507 for (const auto &[key, val] : cpuAndFeatures)
508 attrs.set(key, builder.getStringAttr(val));
509 }
510 }
511
512 // TODO(cir): A bunch of non-call-site function IR attributes from
513 // declaration-specific information, including tail calls,
514 // cmse_nonsecure_entry, and hotpatch support.
515
516 // TODO(cir): Add loader-replaceable attribute here.
517
518 constructFunctionReturnAttributes(info, targetDecl, isThunk, retAttrs);
519 constructFunctionArgumentAttributes(info, targetDecl, isThunk, attrOnCallSite,
520 argAttrs);
521}
522
523bool CIRGenModule::hasStrictReturn(QualType retTy, const Decl *targetDecl) {
524 // As-is msan can not tolerate noundef mismatch between caller and
525 // implementation. Mismatch is possible for e.g. indirect calls from C-caller
526 // into C++. Such mismatches lead to confusing false reports. To avoid
527 // expensive workaround on msan we enforce initialization event in uncommon
528 // cases where it's allowed.
529 if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
530 return true;
531 // C++ explicitly makes returning undefined values UB. C's rule only applies
532 // to used values, so we never mark them noundef for now.
533 if (!getLangOpts().CPlusPlus)
534 return false;
535 if (targetDecl) {
536 if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
537 if (func->isExternC())
538 return false;
539 } else if (const VarDecl *var = dyn_cast<VarDecl>(targetDecl)) {
540 // Function pointer.
541 if (var->isExternC())
542 return false;
543 }
544 }
545
546 // We don't want to be too aggressive with the return checking, unless
547 // it's explicit in the code opts or we're using an appropriate sanitizer.
548 // Try to respect what the programmer intended.
549 return getCodeGenOpts().StrictReturn ||
550 !mayDropFunctionReturn(getASTContext(), retTy) ||
551 getLangOpts().Sanitize.has(SanitizerKind::Return);
552}
553
554bool CIRGenModule::mayDropFunctionReturn(const ASTContext &context,
555 QualType retTy) {
556 // We can't just discard the return value for a record type with a
557 // complex destructor or a non-trivially copyable type.
558 if (const RecordType *recTy =
559 retTy.getCanonicalType()->getAsCanonical<RecordType>()) {
560 if (const auto *record = dyn_cast<CXXRecordDecl>(recTy->getDecl()))
561 return record->hasTrivialDestructor();
562 }
563 return retTy.isTriviallyCopyableType(context);
564}
565
566static bool determineNoUndef(QualType clangTy, CIRGenTypes &types,
567 const cir::CIRDataLayout &layout,
568 const cir::ABIArgInfo &argInfo) {
569 mlir::Type ty = types.convertTypeForMem(clangTy);
571 if (argInfo.isIndirect() || argInfo.isIndirectAliased())
572 return true;
573 if (argInfo.isExtend() && !argInfo.isNoExt())
574 return true;
575
576 if (cir::isSized(ty) && !layout.typeSizeEqualsStoreSize(ty))
577 // TODO: This will result in a modest amount of values not marked noundef
578 // when they could be. We care about values that *invisibly* contain undef
579 // bits from the perspective of LLVM IR.
580 return false;
581
583 // TODO(cir): The calling convention code needs to figure if the
584 // coerced-to-type is larger than the actual type, and remove the noundef
585 // attribute. Classic compiler did it here.
586 if (clangTy->isBitIntType())
587 return true;
588 if (clangTy->isReferenceType())
589 return true;
590 if (clangTy->isNullPtrType())
591 return false;
592 if (clangTy->isMemberPointerType())
593 // TODO: Some member pointers are `noundef`, but it depends on the ABI. For
594 // now, never mark them.
595 return false;
596 if (clangTy->isScalarType()) {
597 if (const ComplexType *Complex = dyn_cast<ComplexType>(clangTy))
598 return determineNoUndef(Complex->getElementType(), types, layout,
599 argInfo);
600 return true;
601 }
602 if (const VectorType *Vector = dyn_cast<VectorType>(clangTy))
603 return determineNoUndef(Vector->getElementType(), types, layout, argInfo);
604 if (const MatrixType *Matrix = dyn_cast<MatrixType>(clangTy))
605 return determineNoUndef(Matrix->getElementType(), types, layout, argInfo);
606 if (const ArrayType *Array = dyn_cast<ArrayType>(clangTy))
607 return determineNoUndef(Array->getElementType(), types, layout, argInfo);
608
609 // TODO: Some structs may be `noundef`, in specific situations.
610 return false;
611}
612
613/// Compute the nofpclass mask for FP types based on language options.
614static unsigned getNoFPClassTestMask(const LangOptions &langOpts) {
615 unsigned mask = 0;
616 if (langOpts.NoHonorInfs)
617 mask |= llvm::fcInf;
618 if (langOpts.NoHonorNaNs)
619 mask |= llvm::fcNan;
620 return mask;
621}
622
623void CIRGenModule::constructFunctionReturnAttributes(
624 const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk,
625 mlir::NamedAttrList &retAttrs) {
626 // Collect attributes from arguments and return values.
627 QualType retTy = info.getReturnType();
628 const cir::ABIArgInfo retInfo = info.getReturnInfo();
629 const cir::CIRDataLayout &layout = getDataLayout();
630
631 if (codeGenOpts.EnableNoundefAttrs && hasStrictReturn(retTy, targetDecl) &&
632 !retTy->isVoidType() &&
633 determineNoUndef(retTy, getTypes(), layout, retInfo))
634 retAttrs.set(mlir::LLVM::LLVMDialect::getNoUndefAttrName(),
635 mlir::UnitAttr::get(&getMLIRContext()));
636
637 if (retTy->hasFloatingRepresentation())
638 if (unsigned mask = getNoFPClassTestMask(getLangOpts()))
639 retAttrs.set(mlir::LLVM::LLVMDialect::getNoFPClassAttrName(),
640 builder.getI64IntegerAttr(mask));
641
642 if (!isThunk) {
643 // TODO(cir): following comment taken from classic codegen, so if anything
644 // happens there, we should reflect it here.
645 // FIXME: fix this properly, https://reviews.llvm.org/D100388
646 if (const auto *refTy = retTy->getAs<ReferenceType>()) {
647 QualType pointeeTy = refTy->getPointeeType();
648 if (!pointeeTy->isIncompleteType() && pointeeTy->isConstantSizeType())
649 retAttrs.set(mlir::LLVM::LLVMDialect::getDereferenceableAttrName(),
650 builder.getI64IntegerAttr(
651 getMinimumObjectSize(pointeeTy).getQuantity()));
652
653 if (getTypes().getTargetAddressSpace(pointeeTy) == 0 &&
654 !codeGenOpts.NullPointerIsValid)
655 retAttrs.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
656 mlir::UnitAttr::get(&getMLIRContext()));
657
658 if (pointeeTy->isObjectType())
659 retAttrs.set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
660 builder.getI64IntegerAttr(
661 getNaturalPointeeTypeAlignment(retTy).getQuantity()));
662 }
663 }
664}
665
666void CIRGenModule::constructFunctionArgumentAttributes(
667 const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk,
668 bool attrOnCallSite, llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs) {
670 // TODO(cir): classic codegen does a lot of work here based on the ABIArgInfo
671 // to set things based on calling convention.
672
673 if (info.isInstanceMethod() && !isThunk) {
674 QualType thisPtrTy = info.arguments()[0];
675 // Member allocation functions are instance methods, but setting attributes
676 // on them is nonsensical and not correct. Make sure we skip that here.
677 if (!thisPtrTy->isVoidPointerType()) {
678 QualType thisTy = thisPtrTy->getPointeeType();
679
680 if (!codeGenOpts.NullPointerIsValid &&
681 getTypes().getTargetAddressSpace(thisPtrTy) == 0) {
682 argAttrs[0].set(mlir::LLVM::LLVMDialect::getDereferenceableAttrName(),
683 builder.getI64IntegerAttr(
684 getMinimumObjectSize(thisTy).getQuantity()));
685 argAttrs[0].set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
686 mlir::UnitAttr::get(&getMLIRContext()));
687 } else {
689
690 if (bytes != 0)
691 argAttrs[0].set(
692 mlir::LLVM::LLVMDialect::getDereferenceableOrNullAttrName(),
693 builder.getI64IntegerAttr(bytes));
694 }
695
696 argAttrs[0].set(
697 mlir::LLVM::LLVMDialect::getAlignAttrName(),
698 builder.getI64IntegerAttr(
699 getNaturalPointeeTypeAlignment(thisPtrTy).getQuantity()));
700
701 // TODO(cir): the classic codegen has a recently-added bunch of logic for
702 // 'dead_on_return' as an attribute. This both doesn't exist in the LLVM
703 // dialect, and is 'too new' at the time of writing this to be considered
704 // stable enough here. For now, we'll leave this as a TODO so that when
705 // we come back, it is hopefully a more stabilized implementation.
706 }
707 }
708
709 // TODO(cir): the logic between 'this', return, and normal arguments hsould
710 // probably be merged at one point, however the logic is unfortunately mildly
711 // different between each in classic codegen, so trying to do anything like
712 // that seems risky at the moment. At one point we should evaluate if at least
713 // dereferenceable, nonnull, and align can be combined.
714 const cir::CIRDataLayout &layout = getDataLayout();
715 const auto *fd = dyn_cast_or_null<FunctionDecl>(targetDecl);
716
717 // Build a parallel array of ParmVarDecls aligned with argAttrs so we can
718 // access parameter-level attributes (e.g. restrict, nonnull) without manual
719 // index arithmetic in the loop.
720 SmallVector<const ParmVarDecl *> parmDecls;
721 parmDecls.reserve(argAttrs.size());
722 if (fd) {
723 if (info.isInstanceMethod())
724 parmDecls.push_back(nullptr);
725 parmDecls.insert(parmDecls.end(), fd->param_begin(), fd->param_end());
726 }
727 parmDecls.resize(argAttrs.size(), nullptr);
728
729 for (const auto &[argAttrList, argCanType, pvd] :
730 llvm::zip_equal(argAttrs, info.arguments(), parmDecls)) {
732 QualType argType = argCanType;
733 const cir::ABIArgInfo argInfo = cir::ABIArgInfo::getDirect();
734
735 if (codeGenOpts.EnableNoundefAttrs &&
736 determineNoUndef(argType, getTypes(), layout, argInfo))
737 argAttrList.set(mlir::LLVM::LLVMDialect::getNoUndefAttrName(),
738 mlir::UnitAttr::get(&getMLIRContext()));
739
741 // TODO(cir): there is plenty of other attributes here added due to ABI
742 // decisions. While these probably won't end up here, we note that the
743 // classic codegen does it here and perhaps we should pay attention to that.
744
745 if (const auto *refTy = argType->getAs<ReferenceType>()) {
746 QualType pointeeTy = refTy->getPointeeType();
747 if (!pointeeTy->isIncompleteType() && pointeeTy->isConstantSizeType())
748 argAttrList.set(mlir::LLVM::LLVMDialect::getDereferenceableAttrName(),
749 builder.getI64IntegerAttr(
750 getMinimumObjectSize(pointeeTy).getQuantity()));
751 if (getTypes().getTargetAddressSpace(pointeeTy) == 0 &&
752 !codeGenOpts.NullPointerIsValid)
753 argAttrList.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
754 mlir::UnitAttr::get(&getMLIRContext()));
755 if (pointeeTy->isObjectType())
756 argAttrList.set(
757 mlir::LLVM::LLVMDialect::getAlignAttrName(),
758 builder.getI64IntegerAttr(
759 getNaturalPointeeTypeAlignment(argType).getQuantity()));
760 }
761
762 if (argType->hasFloatingRepresentation())
763 if (unsigned mask = getNoFPClassTestMask(getLangOpts()))
764 argAttrList.set(mlir::LLVM::LLVMDialect::getNoFPClassAttrName(),
765 builder.getI64IntegerAttr(mask));
766
767 // restrict -> noalias on definitions only (not call sites). Skip
768 // builtins: OGCG applies restrict->noalias in EmitFunctionProlog.
769 if (!attrOnCallSite && pvd && pvd->getType()->isPointerType() &&
770 pvd->getType().isRestrictQualified() && !fd->getBuiltinID())
771 argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
772 mlir::UnitAttr::get(&getMLIRContext()));
773
774 // __attribute__((nonnull)) on pointer parameters. Checks both
775 // per-parameter and function-level nonnull attributes.
776 if (pvd && argType->isAnyPointerType() && !codeGenOpts.NullPointerIsValid) {
777 unsigned srcIdx = pvd->getFunctionScopeIndex();
778 if (pvd->hasAttr<NonNullAttr>() ||
779 (fd->getAttr<NonNullAttr>() &&
780 fd->getAttr<NonNullAttr>()->isNonNull(srcIdx)))
781 argAttrList.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
782 mlir::UnitAttr::get(&getMLIRContext()));
783 }
784 }
785}
786
787/// Returns the canonical formal type of the given C++ method.
793
794/// Adds the formal parameters in FPT to the given prefix. If any parameter in
795/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
796/// TODO(cir): this should be shared with LLVM codegen
797static void appendParameterTypes(const CIRGenTypes &cgt,
800 // Fast path: don't touch param info if we don't need to.
801 if (!fpt->hasExtParameterInfos()) {
802 prefix.append(fpt->param_type_begin(), fpt->param_type_end());
803 return;
804 }
805
806 // In the vast majority of cases, we'll have precisely fpt->getNumParams()
807 // parameters; the only thing that can change this is the presence of
808 // pass_object_size. So, we preallocate for the common case.
809 prefix.reserve(prefix.size() + fpt->getNumParams());
811 fpt->getExtParameterInfos();
812 assert(extInfos.size() == fpt->getNumParams());
813 for (auto [paramType, extInfo] : llvm::zip_equal(
814 llvm::make_range(fpt->param_type_begin(), fpt->param_type_end()),
815 extInfos)) {
816 prefix.push_back(paramType);
817 if (extInfo.hasPassObjectSize())
818 prefix.push_back(cgt.getASTContext().getCanonicalSizeType());
819 }
820}
821
822const CIRGenFunctionInfo &
824 auto *md = cast<CXXMethodDecl>(gd.getDecl());
825
827 argTypes.push_back(deriveThisType(md->getParent(), md));
828
829 bool passParams = true;
830
831 if (auto *cd = dyn_cast<CXXConstructorDecl>(md)) {
832 // A base class inheriting constructor doesn't get forwarded arguments
833 // needed to construct a virtual base (or base class thereof)
834 if (auto inherited = cd->getInheritedConstructor())
835 passParams = inheritingCtorHasParams(inherited, gd.getCtorType());
836 }
837
839
840 if (passParams)
841 appendParameterTypes(*this, argTypes, fpt);
842
843 // The structor signature may include implicit parameters.
844 [[maybe_unused]] CIRGenCXXABI::AddedStructorArgCounts addedArgs =
845 theCXXABI.buildStructorSignature(gd, argTypes);
847
848 RequiredArgs required =
849 (passParams && md->isVariadic() ? RequiredArgs(argTypes.size())
851
852 CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front()
853 : theCXXABI.hasMostDerivedReturn(gd)
854 ? astContext.VoidPtrTy
855 : astContext.VoidTy;
856
857 assert(!theCXXABI.hasThisReturn(gd) &&
858 "Please send PR with a test and remove this");
859
862
863 return arrangeCIRFunctionInfo(resultType, /*isInstanceMethod=*/true, argTypes,
864 fpt->getExtInfo(), required);
865}
866
867/// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR
868/// qualification. Either or both of `rd` and `md` may be null. A null `rd`
869/// indicates that there is no meaningful 'this' type, and a null `md` can occur
870/// when calling a method pointer.
872 const CXXMethodDecl *md) {
873 CanQualType recTy;
874 if (rd) {
876 } else {
877 // This can happen with the MS ABI. It shouldn't need anything more than
878 // setting recTy to VoidTy here, but we're flagging it for now because we
879 // don't have the full handling implemented.
880 cgm.errorNYI("deriveThisType: no record decl");
881 recTy = getASTContext().VoidTy;
882 }
883
884 if (md)
885 recTy = CanQualType::CreateUnsafe(getASTContext().getAddrSpaceQualType(
886 recTy, md->getMethodQualifiers().getAddressSpace()));
887 return getASTContext().getPointerType(recTy);
888}
889
890/// Arrange the CIR function layout for a value of the given function type, on
891/// top of any implicit parameters already stored.
892static const CIRGenFunctionInfo &
893arrangeCIRFunctionInfo(CIRGenTypes &cgt, bool instanceMethod,
897 RequiredArgs required =
900 appendParameterTypes(cgt, prefix, fpt);
901 CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
902 return cgt.arrangeCIRFunctionInfo(resultType, instanceMethod, prefix,
903 fpt->getExtInfo(), required);
904}
905
907 const VarDecl *param,
908 SourceLocation loc) {
909 // StartFunction converted the ABI-lowered parameter(s) into a local alloca.
910 // We need to turn that into an r-value suitable for emitCall
911 Address local = getAddrOfLocalVar(param);
912
913 QualType type = param->getType();
914
915 // GetAddrOfLocalVar returns a pointer-to-pointer for references, but the
916 // argument needs to be the original pointer.
917 if (type->isReferenceType()) {
918 args.add(
919 RValue::get(builder.createLoad(getLoc(param->getSourceRange()), local)),
920 type);
921 } else if (getLangOpts().ObjCAutoRefCount) {
922 cgm.errorNYI(param->getSourceRange(),
923 "emitDelegateCallArg: ObjCAutoRefCount");
924 // For the most part, we just need to load the alloca, except that aggregate
925 // r-values are actually pointers to temporaries.
926 } else {
927 args.add(convertTempToRValue(local, type, loc), type);
928 }
929
930 // Deactivate the cleanup for the callee-destructed param that was pushed.
932 if (type->isRecordType() &&
933 type->castAsRecordDecl()->isParamDestroyedInCallee() &&
934 param->needsDestruction(getContext())) {
935 cgm.errorNYI(param->getSourceRange(),
936 "emitDelegateCallArg: callee-destructed param");
937 }
938}
939
940static const CIRGenFunctionInfo &
942 const CallArgList &args,
943 const FunctionType *fnType) {
944
946
947 if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
948 // A free function call has no extra prefix arguments. Note that
949 // getFromProtoWithExtraSlots already accounts for the prototype's
950 // pass_object_size parameters; adding them here too would double-count
951 // them and make the signature claim more required arguments than `args`
952 // actually holds.
953 if (proto->isVariadic())
954 required = RequiredArgs::getFromProtoWithExtraSlots(proto, 0);
957 cgm.errorNYI("call to function without a prototype");
958
960 for (const CallArg &arg : args)
961 argTypes.push_back(cgt.getASTContext().getCanonicalParamType(arg.ty));
962
964
966 return cgt.arrangeCIRFunctionInfo(retType, /*isInstanceMethod=*/false,
967 argTypes, fnType->getExtInfo(), required);
968}
969
970/// Arrange a call to a C++ method, passing the given arguments.
971///
972/// extraPrefixArgs is the number of ABI-specific args passed after the `this`
973/// parameter.
974/// passProtoArgs indicates whether `args` has args for the parameters in the
975/// given CXXConstructorDecl.
977 const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind,
978 unsigned extraPrefixArgs, unsigned extraSuffixArgs, bool passProtoArgs) {
979
980 // FIXME: Kill copy.
982 for (const auto &arg : args)
983 argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
984
985 // +1 for implicit this, which should always be args[0]
986 unsigned totalPrefixArgs = 1 + extraPrefixArgs;
987
989 RequiredArgs required = passProtoArgs
991 fpt, totalPrefixArgs + extraSuffixArgs)
993
994 GlobalDecl gd(d, ctorKind);
995 if (theCXXABI.hasThisReturn(gd))
996 cgm.errorNYI(d->getSourceRange(),
997 "arrangeCXXConstructorCall: hasThisReturn");
998 if (theCXXABI.hasMostDerivedReturn(gd))
999 cgm.errorNYI(d->getSourceRange(),
1000 "arrangeCXXConstructorCall: hasMostDerivedReturn");
1001 CanQualType resultType = astContext.VoidTy;
1002
1005
1006 return arrangeCIRFunctionInfo(resultType, /*isInstanceMethod=*/true, argTypes,
1007 fpt->getExtInfo(), required);
1008}
1009
1010/// Arrange a call to a C++ method, passing the given arguments.
1011///
1012/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It
1013/// does not count `this`.
1015 const CallArgList &args, const FunctionProtoType *proto,
1016 RequiredArgs required, unsigned numPrefixArgs) {
1018 assert(numPrefixArgs + 1 <= args.size() &&
1019 "Emitting a call with less args than the required prefix?");
1020
1021 // FIXME: Kill copy.
1023 for (const CallArg &arg : args)
1024 argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
1025
1029 /*isInstanceMethod=*/true, argTypes, proto->getExtInfo(), required);
1030}
1031
1032const CIRGenFunctionInfo &
1034 const FunctionType *fnType) {
1035 return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
1036}
1037
1038const CIRGenFunctionInfo &
1040 const CallArgList &args) {
1042 for (const CallArg &arg : args)
1043 argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
1044
1045 CanQualType retType = resultType->getCanonicalTypeUnqualified();
1046 return arrangeCIRFunctionInfo(retType, /*isInstanceMethod=*/false, argTypes,
1048}
1049
1050/// Arrange the argument and result information for a declaration or definition
1051/// of the given C++ non-static member function. The member function must be an
1052/// ordinary function, i.e. not a constructor or destructor.
1053const CIRGenFunctionInfo &
1055 assert(!isa<CXXConstructorDecl>(md) && "wrong method for constructors!");
1056 assert(!isa<CXXDestructorDecl>(md) && "wrong method for destructors!");
1057
1058 auto prototype =
1061
1062 // Mirrors classic CodeGen's check at CGCall.cpp. C++23 explicit-object
1063 // member functions (P0847R7, `void f(this Self&&)`) do not receive an
1064 // implicit `this`; the explicit object parameter takes its place at the
1065 // AST level and appears as the first parameter of the FunctionProtoType.
1066 // Arrange them as free functions so we don't prepend a stale implicit
1067 // `this` to the parameter list, which would produce a CIRGenFunctionInfo
1068 // with one more argument than the matching cir.func type and trip the
1069 // assertion in setArgAttrs.
1071 // The abstract case is perfectly fine.
1072 auto *thisType = theCXXABI.getThisArgumentTypeForMethod(md);
1073 return arrangeCXXMethodType(thisType, prototype.getTypePtr(), md);
1074 }
1075
1076 return arrangeFreeFunctionType(prototype);
1077}
1078
1079/// Arrange the argument and result information for a call to an unknown C++
1080/// non-static member function of the given abstract type. (A null RD means we
1081/// don't have any meaningful "this" argument type, so fall back to a generic
1082/// pointer type). The member fucntion must be an ordinary function, i.e. not a
1083/// constructor or destructor.
1084const CIRGenFunctionInfo &
1086 const FunctionProtoType *fpt,
1087 const CXXMethodDecl *md) {
1089
1090 // Add the 'this' pointer.
1091 argTypes.push_back(deriveThisType(rd, md));
1092
1094 return ::arrangeCIRFunctionInfo(
1095 *this, /*isInstanceMethod=*/true, argTypes,
1097}
1098
1099/// Arrange the argument and result information for the declaration or
1100/// definition of the given function.
1101const CIRGenFunctionInfo &
1103 if (const auto *md = dyn_cast<CXXMethodDecl>(fd))
1104 if (md->isInstance())
1105 return arrangeCXXMethodDeclaration(md);
1106
1108
1109 assert(isa<FunctionType>(funcTy));
1110 // TODO: setCUDAKernelCallingConvention
1112
1113 // When declaring a function without a prototype, always use a non-variadic
1114 // type.
1115 if (CanQual<FunctionNoProtoType> noProto =
1116 funcTy.getAs<FunctionNoProtoType>()) {
1119 return arrangeCIRFunctionInfo(noProto->getReturnType(),
1120 /*isInstanceMethod=*/false, {},
1121 noProto->getExtInfo(), RequiredArgs::All);
1122 }
1123
1125}
1126
1127RValue CallArg::getRValue(CIRGenFunction &cgf, mlir::Location loc) const {
1128 if (!hasLV)
1129 return rv;
1130 LValue copy = cgf.makeAddrLValue(cgf.createMemTemp(ty, loc), ty);
1132 lv.isVolatile());
1133 isUsed = true;
1134 return RValue::getAggregate(copy.getAddress());
1135}
1136
1138 SourceLocation argLoc,
1139 AbstractCallee ac, unsigned paramNum) {
1140 if (!ac.getDecl() || !(sanOpts.has(SanitizerKind::NonnullAttribute) ||
1141 sanOpts.has(SanitizerKind::NullabilityArg)))
1142 return;
1143 cgm.errorNYI("non-null arg check is NYI");
1144}
1145
1146static cir::CIRCallOpInterface
1147emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
1148 cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
1149 cir::FuncOp directFuncOp,
1150 const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
1151 const mlir::NamedAttrList &attrs,
1153 const mlir::NamedAttrList &retAttrs) {
1154 CIRGenBuilderTy &builder = cgf.getBuilder();
1155
1157
1158 assert(builder.getInsertionBlock() && "expected valid basic block");
1159
1160 cir::CallOp op;
1161 if (indirectFuncTy) {
1162 // TODO(cir): Set calling convention for indirect calls.
1164 op = builder.createIndirectCallOp(callLoc, indirectFuncVal, indirectFuncTy,
1165 cirCallArgs, attrs, argAttrs, retAttrs);
1166 } else {
1167 op = builder.createCallOp(callLoc, directFuncOp, cirCallArgs, attrs,
1168 argAttrs, retAttrs);
1169 }
1170
1171 return op;
1172}
1173
1174const CIRGenFunctionInfo &
1178 return ::arrangeCIRFunctionInfo(*this, /*isInstanceMethod=*/false, argTypes,
1179 fpt);
1180}
1181
1182const CIRGenFunctionInfo &
1184 CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
1186 return arrangeCIRFunctionInfo(resultType, /*isInstanceMethod=*/false, {},
1187 fnpt->getExtInfo(), RequiredArgs(0));
1188}
1189
1191 const CIRGenCallee &callee,
1193 const CallArgList &args,
1194 cir::CIRCallOpInterface *callOp,
1195 bool isMustTail, mlir::Location loc) {
1196 QualType retTy = funcInfo.getReturnType();
1197 cir::FuncType cirFuncTy = getTypes().getFunctionType(funcInfo);
1198
1199 SmallVector<mlir::Value, 16> cirCallArgs(args.size());
1200
1201 const Decl *targetDecl = callee.getAbstractInfo().getCalleeDecl().getDecl();
1202 const FunctionDecl *callerDecl = dyn_cast_or_null<FunctionDecl>(curCodeDecl);
1203 const FunctionDecl *calleeDecl = dyn_cast_or_null<FunctionDecl>(targetDecl);
1204
1206
1207 // Translate all of the arguments as necessary to match the CIR lowering.
1208 for (auto [argNo, arg, canQualArgType] :
1209 llvm::enumerate(args, funcInfo.argTypes())) {
1210
1211 // Insert a padding argument to ensure proper alignment.
1213
1214 mlir::Type argType = convertType(canQualArgType);
1215 if (!mlir::isa<cir::RecordType>(argType) &&
1216 !mlir::isa<cir::ComplexType>(argType)) {
1217 mlir::Value v;
1218 if (arg.isAggregate())
1219 cgm.errorNYI(loc, "emitCall: aggregate call argument");
1220 v = arg.getKnownRValue().getValue();
1221
1222 // We might have to widen integers, but we should never truncate.
1223 if (argType != v.getType() && mlir::isa<cir::IntType>(v.getType()))
1224 cgm.errorNYI(loc, "emitCall: widening integer call argument");
1225
1226 // If we have a pointer argument and there's an address space mismatch,
1227 // insert an address_space cast to match the expected function signature.
1228 if (argType != v.getType()) {
1229 auto argPtrTy = mlir::dyn_cast<cir::PointerType>(argType);
1230 auto vPtrTy = mlir::dyn_cast<cir::PointerType>(v.getType());
1231 if (argPtrTy && vPtrTy &&
1232 argPtrTy.getPointee() == vPtrTy.getPointee() &&
1233 argPtrTy.getAddrSpace() != vPtrTy.getAddrSpace()) {
1234 v = performAddrSpaceCast(v, argPtrTy);
1235 }
1236 }
1237
1238 // If the argument doesn't match, perform a bitcast to coerce it. This
1239 // can happen due to trivial type mismatches.
1240 // TODO(cir): When getFunctionType is added, assert that this isn't
1241 // needed.
1243 cirCallArgs[argNo] = v;
1244 } else {
1245 Address src = Address::invalid();
1246 if (!arg.isAggregate()) {
1247 src = createMemTemp(arg.ty, loc, "coerce");
1248 arg.copyInto(*this, src, loc);
1249 } else {
1250 src = arg.hasLValue() ? arg.getKnownLValue().getAddress()
1251 : arg.getKnownRValue().getAggregateAddress();
1252 }
1253
1254 // Fast-isel and the optimizer generally like scalar values better than
1255 // FCAs, so we flatten them if this is safe to do for this argument.
1256 mlir::Type srcTy = src.getElementType();
1257 // FIXME(cir): get proper location for each argument.
1258 mlir::Location argLoc = loc;
1259
1260 // If the source type is smaller than the destination type of the
1261 // coerce-to logic, copy the source value into a temp alloca the size
1262 // of the destination type to allow loading all of it. The bits past
1263 // the source value are left undef.
1264 // FIXME(cir): add data layout info and compare sizes instead of
1265 // matching the types.
1266 //
1267 // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
1268 // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
1269 // if (SrcSize < DstSize) {
1271 if (srcTy != argType) {
1272 cgm.errorNYI(loc, "emitCall: source type does not match argument type");
1273 } else {
1274 // FIXME(cir): this currently only runs when the types are exactly the
1275 // same, but should be when alloc sizes are the same, fix this as soon
1276 // as datalayout gets introduced.
1278 }
1279
1280 // assert(NumCIRArgs == STy.getMembers().size());
1281 // In LLVMGen: Still only pass the struct without any gaps but mark it
1282 // as such somehow.
1283 //
1284 // In CIRGen: Emit a load from the "whole" struct,
1285 // which shall be broken later by some lowering step into multiple
1286 // loads.
1288 cirCallArgs[argNo] = builder.createLoad(argLoc, src);
1289 }
1290 }
1291
1292 const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);
1293 mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
1294
1296
1297 mlir::NamedAttrList attrs;
1298 std::vector<mlir::NamedAttrList> argAttrs(funcInfo.arguments().size());
1299 mlir::NamedAttrList retAttrs;
1300 StringRef funcName;
1301 if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
1302 funcName = calleeFuncOp.getName();
1303
1306 cir::CallingConv callingConv;
1307 cir::SideEffect sideEffect;
1308 cgm.constructAttributeList(funcName, funcInfo, callee.getAbstractInfo(),
1309 attrs, argAttrs, retAttrs, callingConv, sideEffect,
1310 /*attrOnCallSite=*/true, /*isThunk=*/false);
1311
1312 auto resolvedFuncOpFromGlobal = [&](mlir::Operation *op) -> cir::FuncOp {
1313 if (auto fnOp = dyn_cast<cir::FuncOp>(op))
1314 return fnOp;
1315 if (auto getGlobalOp = dyn_cast<cir::GetGlobalOp>(op)) {
1316 // FIXME(cir): This peephole optimization avoids indirect calls for
1317 // builtins. This should be fixed in the builtin declaration instead by
1318 // not emitting an unecessary get_global in the first place. However,
1319 // this is also used for no-prototype functions.
1320 mlir::Operation *globalOp = cgm.getGlobalValue(getGlobalOp.getName());
1321 assert(globalOp && "undefined global function");
1322 return cast<cir::FuncOp>(globalOp);
1323 }
1324 return nullptr;
1325 };
1326
1327 cir::FuncType indirectFuncTy;
1328 mlir::Value indirectFuncVal;
1329 cir::FuncOp directFuncOp;
1330
1331 // If the callee resolves to a FuncOp whose stored signature differs from
1332 // this call site's expected signature, the CIR verifier would reject the
1333 // mismatched types. This happens, for example, when two declarations share a
1334 // mangled name via __asm__ renaming (glibc's __REDIRECT_NTH pattern) but
1335 // disagree about a struct argument type. If that happens, we demote the
1336 // direct call to an indirect call through a function-pointer bitcast typed
1337 // at the call site.
1338 if (cir::FuncOp candidate = resolvedFuncOpFromGlobal(calleePtr)) {
1339 if (candidate.getFunctionType() == cirFuncTy) {
1340 directFuncOp = candidate;
1341 } else {
1342 mlir::Value addr = cir::GetGlobalOp::create(
1343 builder, loc, cir::PointerType::get(candidate.getFunctionType()),
1344 candidate.getSymName());
1345 indirectFuncTy = cirFuncTy;
1346 indirectFuncVal =
1347 builder.createBitcast(addr, cir::PointerType::get(cirFuncTy));
1348 }
1349 } else {
1350 [[maybe_unused]] mlir::ValueTypeRange<mlir::ResultRange> resultTypes =
1351 calleePtr->getResultTypes();
1352 [[maybe_unused]] auto funcPtrTy =
1353 mlir::dyn_cast<cir::PointerType>(resultTypes.front());
1354 assert(funcPtrTy && mlir::isa<cir::FuncType>(funcPtrTy.getPointee()) &&
1355 "expected pointer to function");
1356
1357 indirectFuncTy = cirFuncTy;
1358 indirectFuncVal = calleePtr->getResult(0);
1359 }
1360
1364
1365 bool cannotThrow = attrs.getNamed("nothrow").has_value();
1366 bool isInvoke = !cannotThrow && isCatchOrCleanupRequired();
1367
1368 mlir::Location callLoc = loc;
1369 cir::CIRCallOpInterface theCall =
1370 emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
1371 cirCallArgs, isInvoke, attrs, argAttrs, retAttrs);
1372
1373 if (callOp)
1374 *callOp = theCall;
1375
1376 // Sema/emitAttributedStmt (see
1377 // https://github.com/llvm/llvm-project/issues/214764) should one-day enforce
1378 // that only one of these is valid at a time. For now, we have the same 'bug'
1379 // as classic codegen where we can end up having BOTH of these.
1381 theCall.setInlineKind(cir::InlineKind::NoInline);
1383 !cgm.getTargetCIRGenInfo().wouldInliningViolateFunctionCallABI(
1384 callerDecl, calleeDecl))
1385 theCall.setInlineKind(cir::InlineKind::AlwaysInline);
1386
1387 if (isMustTail) {
1388 // PPC/MIPS have some diagnostics for classic-codegen, but we don't support
1389 // them yet.
1390 const llvm::Triple &triple = getTarget().getTriple();
1391 if (triple.isPPC() || triple.isMIPS()) {
1392 cgm.errorNYI(mustTailCall->getBeginLoc(),
1393 "musttail call target legality checks");
1394 return getUndefRValue(retTy);
1395 }
1396
1397 // Musttail is required to return immediately. Classic codegen does some
1398 // work here to go through the exception handling scopes to put them before
1399 // the call (it seems?) since musttail must be the last op before the
1400 // return. For now, skip this so we an do it later.
1401 if (ehStack.stable_begin() != prologueCleanupDepth) {
1402 cgm.errorNYI(mustTailCall->getBeginLoc(),
1403 "musttail call that skips cleanups");
1404 return getUndefRValue(retTy);
1405 }
1406
1407 theCall->setAttr(cir::CIRDialect::getMustTailAttrName(),
1408 builder.getUnitAttr());
1409
1410 if (isa<cir::VoidType>(convertType(retTy)))
1411 cir::ReturnOp::create(builder, loc);
1412 else
1413 cir::ReturnOp::create(builder, loc, theCall->getResult(0));
1414
1415 // Musttail must return immediately, so we just do that. All of the below
1416 // stuff is effectively UB if this is a musttail, so just do a return
1417 // immediately.
1418 builder.createBlock(builder.getBlock()->getParent());
1419 return getUndefRValue(retTy);
1420 }
1421
1423
1424 mlir::Type retCIRTy = convertType(retTy);
1425 if (isa<cir::VoidType>(retCIRTy))
1426 return getUndefRValue(retTy);
1427 switch (getEvaluationKind(retTy)) {
1428 case cir::TEK_Aggregate: {
1429 Address destPtr = returnValue.getValue();
1430
1431 if (!destPtr.isValid())
1432 destPtr = createMemTemp(retTy, callLoc, getCounterAggTmpAsString());
1433
1434 mlir::ResultRange results = theCall->getOpResults();
1435 assert(results.size() <= 1 && "multiple returns from a call");
1436
1437 SourceLocRAIIObject loc{*this, callLoc};
1438 emitAggregateStore(results[0], destPtr);
1439 return RValue::getAggregate(destPtr);
1440 }
1441 case cir::TEK_Scalar: {
1442 mlir::ResultRange results = theCall->getOpResults();
1443 assert(results.size() == 1 && "unexpected number of returns");
1444
1445 // If the argument doesn't match, perform a bitcast to coerce it. This
1446 // can happen due to trivial type mismatches.
1447 if (results[0].getType() != retCIRTy)
1448 cgm.errorNYI(loc, "bitcast on function return value");
1449
1450 mlir::Region *region = builder.getBlock()->getParent();
1451 if (region != theCall->getParentRegion())
1452 cgm.errorNYI(loc, "function calls with cleanup");
1453
1454 return RValue::get(results[0]);
1455 }
1456 case cir::TEK_Complex: {
1457 mlir::ResultRange results = theCall->getOpResults();
1458 assert(!results.empty() &&
1459 "Expected at least one result for complex rvalue");
1460 return RValue::getComplex(results[0]);
1461 }
1462 }
1463 llvm_unreachable("Invalid evaluation kind");
1464}
1465
1467 mlir::Location loc) const {
1468 LValue dst = cgf.makeAddrLValue(addr, ty);
1469 if (!hasLV && rv.isScalar())
1470 cgf.cgm.errorNYI(loc, "copyInto scalar value");
1471 else if (!hasLV && rv.isComplex())
1472 cgf.emitStoreOfComplex(loc, rv.getComplexValue(), dst, /*isInit=*/true);
1473 else
1474 cgf.cgm.errorNYI(loc, "copyInto hasLV");
1475 isUsed = true;
1476}
1477
1478mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc,
1479 cir::FuncOp callee,
1481 mlir::NamedAttrList attrs) {
1482
1483 // TODO(cir): set the calling convention to this runtime call.
1485
1486 cir::CallOp call = builder.createCallOp(loc, callee, args);
1487 assert(call->getNumResults() <= 1 &&
1488 "runtime functions have at most 1 result");
1489
1490 if (!attrs.empty())
1491 call->setAttrs(attrs);
1492
1493 if (call->getNumResults() == 0)
1494 return nullptr;
1495
1496 return call->getResult(0);
1497}
1498
1500 clang::QualType argType) {
1501 assert(argType->isReferenceType() == e->isGLValue() &&
1502 "reference binding to unmaterialized r-value!");
1503
1504 if (e->isGLValue()) {
1505 assert(e->getObjectKind() == OK_Ordinary);
1506 return args.add(emitReferenceBindingToExpr(e), argType);
1507 }
1508
1509 bool hasAggregateEvalKind = hasAggregateEvaluationKind(argType);
1510
1511 // For callee-destructed parameters (trivial_abi, MS ABI), create an
1512 // aggregate temp and let the callee destroy it.
1513 if (argType->isRecordType() &&
1515 AggValueSlot slot = createAggTemp(argType, getLoc(e->getSourceRange()),
1517
1518 bool destroyedInCallee = true;
1519 if (const auto *rd = argType->getAsCXXRecordDecl())
1520 destroyedInCallee = rd->hasNonTrivialDestructor();
1521
1522 if (destroyedInCallee)
1524
1525 emitAggExpr(e, slot);
1526 RValue rv = slot.asRValue();
1527 args.add(rv, argType);
1528
1529 if (destroyedInCallee && getLangOpts().Exceptions)
1530 cgm.errorNYI(e->getSourceRange(),
1531 "callee-destructed param with exceptions");
1532 return;
1533 }
1534
1535 if (hasAggregateEvalKind && isa<ImplicitCastExpr>(e) &&
1536 cast<CastExpr>(e)->getCastKind() == CK_LValueToRValue) {
1537 LValue lv = emitLValue(cast<CastExpr>(e)->getSubExpr());
1538 assert(lv.isSimple());
1539 args.addUncopiedAggregate(lv, argType);
1540 return;
1541 }
1542
1543 args.add(emitAnyExprToTemp(e), argType);
1544}
1545
1546QualType CIRGenFunction::getVarArgType(const Expr *arg) {
1547 // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC
1548 // implicitly widens null pointer constants that are arguments to varargs
1549 // functions to pointer-sized ints.
1550 if (!getTarget().getTriple().isOSWindows())
1551 return arg->getType();
1552
1553 assert(!cir::MissingFeatures::msabi());
1554 cgm.errorNYI(arg->getSourceRange(), "getVarArgType: NYI for Windows target");
1555 return arg->getType();
1556}
1557
1558/// Similar to emitAnyExpr(), however, the result will always be accessible
1559/// even if no aggregate location is provided.
1562
1564 aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()),
1566
1567 return emitAnyExpr(e, aggSlot);
1568}
1569
1571 CallArgList &args, PrototypeWrapper prototype,
1572 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
1573 AbstractCallee callee, unsigned paramsToSkip) {
1575
1577
1578 // First, if a prototype was provided, use those argument types.
1579 bool isVariadic = false;
1580 if (prototype.p) {
1582
1583 const auto *fpt = cast<const FunctionProtoType *>(prototype.p);
1584 isVariadic = fpt->isVariadic();
1586 argTypes.assign(fpt->param_type_begin() + paramsToSkip,
1587 fpt->param_type_end());
1588 }
1589
1590 // If we still have any arguments, emit them using the type of the argument.
1591 for (const clang::Expr *a : llvm::drop_begin(argRange, argTypes.size()))
1592 argTypes.push_back(isVariadic ? getVarArgType(a) : a->getType());
1593 assert(argTypes.size() == (size_t)(argRange.end() - argRange.begin()));
1594
1595 // We must evaluate arguments from right to left in the MS C++ ABI, because
1596 // arguments are destroyed left to right in the callee. As a special case,
1597 // there are certain language constructs taht require left-to-right
1598 // evaluation, and in those cases we consider the evaluation order requirement
1599 // to trump the "destruction order is reverse construction order" guarantee.
1600 auto leftToRight = true;
1601 assert(!cir::MissingFeatures::msabi());
1602
1603 auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,
1604 RValue emittedArg) {
1605 if (!callee.hasFunctionDecl() || i >= callee.getNumParams())
1606 return;
1607 auto *ps = callee.getParamDecl(i)->getAttr<PassObjectSizeAttr>();
1608 if (!ps)
1609 return;
1610
1612 assert(emittedArg.getValue() && "We emitted nothing for the arg?");
1613 mlir::Value v = evaluateOrEmitBuiltinObjectSize(
1614 arg, ps->getType(), cast<cir::IntType>(cgm.sizeTy),
1615 emittedArg.getValue(), ps->isDynamic());
1616 args.add(RValue::get(v), sizeTy);
1617 // When emitting right-to-left, the size arg was appended after the
1618 // pointer arg; swap them so the size follows the pointer in the final
1619 // argument list after the outer reverse.
1620 if (!leftToRight)
1621 std::iter_swap(args.rbegin(), std::next(args.rbegin()));
1622 };
1623
1624 // Evaluate each argument in the appropriate order.
1625 size_t callArgsStart = args.size();
1626 for (size_t i = 0; i != argTypes.size(); ++i) {
1627 size_t idx = leftToRight ? i : argTypes.size() - i - 1;
1628 CallExpr::const_arg_iterator currentArg = argRange.begin() + idx;
1629 size_t initialArgSize = args.size();
1630
1631 emitCallArg(args, *currentArg, argTypes[idx]);
1632
1633 // In particular, we depend on it being the last arg in Args, and the
1634 // objectsize bits depend on there only being one arg if !LeftToRight.
1635 assert(initialArgSize + 1 == args.size() &&
1636 "The code below depends on only adding one arg per emitCallArg");
1637 (void)initialArgSize;
1638
1639 // Since pointer argument are never emitted as LValue, it is safe to emit
1640 // non-null argument check for r-value only.
1641 if (!args.back().hasLValue()) {
1642 RValue rvArg = args.back().getKnownRValue();
1644 maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);
1645 }
1646
1647 if (!leftToRight)
1648 std::reverse(args.begin() + callArgsStart, args.end());
1649 }
1650}
1651
1652// FIXME(cir): This is identical to the version from classic-codegen, we should
1653// figure out how to move this to a common location.
1655 CXXCtorType type) {
1656 // Parameters are unnecessary if we're constructing a base class subobject
1657 // and the inherited constructor lives in a virtual base.
1658 return type == Ctor_Complete ||
1659 !inherited.getShadowDecl()->constructsVirtualBase() ||
1661}
static StringRef bytes(const std::vector< T, Allocator > &v)
static void addTrivialDefaultFunctionAttributes(mlir::MLIRContext *mlirCtx, StringRef name, bool hasOptNoneAttr, const CodeGenOptions &codeGenOpts, const LangOptions &langOpts, bool attrOnCallSite, mlir::NamedAttrList &attrs)
Add default attributes to a function, which have merge semantics under -mlink-builtin-bitcode and sho...
static void addNoBuiltinAttributes(mlir::MLIRContext &ctx, mlir::NamedAttrList &attrs, const LangOptions &langOpts, const NoBuiltinAttr *nba=nullptr)
static bool determineNoUndef(QualType clangTy, CIRGenTypes &types, const cir::CIRDataLayout &layout, const cir::ABIArgInfo &argInfo)
static void addDenormalModeAttrs(llvm::DenormalMode fpDenormalMode, llvm::DenormalMode fp32DenormalMode, mlir::NamedAttrList &attrs)
Add denormal-fp-math and denormal-fp-math-f32 as appropriate for the requested denormal behavior,...
static unsigned getNoFPClassTestMask(const LangOptions &langOpts)
Compute the nofpclass mask for FP types based on language options.
static void addMergeableDefaultFunctionAttributes(const CodeGenOptions &codeGenOpts, mlir::NamedAttrList &attrs)
Add default attributes to a function, which have merge semantics under -mlink-builtin-bitcode and sho...
static void appendParameterTypes(const CIRGenTypes &cgt, SmallVectorImpl< CanQualType > &prefix, CanQual< FunctionProtoType > fpt)
Adds the formal parameters in FPT to the given prefix.
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, llvm::ArrayRef< mlir::NamedAttrList > argAttrs, const mlir::NamedAttrList &retAttrs)
static void addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder, mlir::NamedAttrList &attrs, const FunctionProtoType *fpt)
static llvm::StringLiteral getZeroCallUsedRegsKindStr(llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind k)
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)
static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, bool instanceMethod, 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...
TokenType getType() const
Returns the token's type, e.g.
static StringRef getTriple(const Command &Job)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
llvm::json::Array Array
static bool isVirtualCall(const CallExpr *CE)
bool isIndirectAliased() const
Definition ABIArgInfo.h:80
bool isExtend() const
Definition ABIArgInfo.h:72
bool isNoExt() const
Definition ABIArgInfo.h:76
static ABIArgInfo getDirect(mlir::Type ty=nullptr)
Definition ABIArgInfo.h:56
bool isIndirect() const
Definition ABIArgInfo.h:68
cir::CallOp createIndirectCallOp(mlir::Location loc, mlir::Value indirectTarget, cir::FuncType funcType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={})
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={})
bool typeSizeEqualsStoreSize(mlir::Type ty) const
Returns true if no extra padding bits are needed when storing the specified type.
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 getCanonicalSizeType() const
CanQualType VoidTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:942
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3836
mlir::Type getElementType() const
Definition Address.h:125
static Address invalid()
Definition Address.h:76
bool isValid() const
Definition Address.h:77
An aggregate value slot.
void setExternallyDestructed(bool destructed=true)
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
static CIRGenFunctionInfo * create(FunctionType::ExtInfo info, bool instanceMethod, CanQualType resultType, llvm::ArrayRef< CanQualType > argTypes, RequiredArgs required)
llvm::MutableArrayRef< CanQualType > argTypes()
llvm::ArrayRef< CanQualType > arguments() const
const_arg_iterator argTypesBegin() const
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.
EHScopeStack::stable_iterator prologueCleanupDepth
The cleanup depth enclosing all the cleanups associated with the parameters.
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.
void emitAggregateCopy(LValue dest, LValue src, QualType eltTy, AggValueSlot::Overlap_t mayOverlap, bool isVolatile=false)
Emit an aggregate copy.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAggregateStore(mlir::Value value, Address dest)
mlir::Value performAddrSpaceCast(mlir::Value v, mlir::Type destTy) const
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, bool isDynamic)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
AggValueSlot createAggTemp(QualType ty, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr)
Create a temporary memory object for the given aggregate type.
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
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.
void emitCallArg(CallArgList &args, const clang::Expr *e, clang::QualType argType)
const clang::Decl * curCodeDecl
This is the inner-most code context, which includes blocks.
CIRGenBuilderTy & getBuilder()
void emitNonNullArgCheck(RValue rv, QualType argType, SourceLocation argLoc, AbstractCallee ac, unsigned paramNum)
Create a check for a function parameter that may potentially be declared as non-null.
mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, llvm::ArrayRef< mlir::Value > args={}, mlir::NamedAttrList attrs={})
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
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, mlir::Location loc)
bool inAlwaysInlineAttributedStmt
True if the current statement has always_inline attribute.
bool inNoInlineAttributedStmt
True if the current statement has noinline attribute.
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...
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
This class organizes the cross-function state that is used while generating CIR code.
llvm::StringRef getMangledName(clang::GlobalDecl gd)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
void addDefaultFunctionAttributes(StringRef name, bool hasOptNoneAttr, bool attrOnCallSite, mlir::NamedAttrList &attrs)
Helper function for constructAttributeList/others.
CIRGenBuilderTy & getBuilder()
CharUnits getMinimumObjectSize(QualType ty)
Returns the minimum object size for an object of the given type.
const cir::CIRDataLayout getDataLayout() const
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
void constructAttributeList(llvm::StringRef name, const CIRGenFunctionInfo &info, CIRGenCalleeInfo calleeInfo, mlir::NamedAttrList &attrs, llvm::MutableArrayRef< mlir::NamedAttrList > argAttrs, mlir::NamedAttrList &retAttrs, cir::CallingConv &callingConv, cir::SideEffect &sideEffect, bool attrOnCallSite, bool isThunk)
Get the CIR attributes and calling convention to use for a particular function type.
const TargetCIRGenInfo & getTargetCIRGenInfo()
mlir::MLIRContext & getMLIRContext()
CIRGenCXXABI & getCXXABI() const
clang::CharUnits getNaturalPointeeTypeAlignment(clang::QualType t, LValueBaseInfo *baseInfo=nullptr)
This class organizes the cross-module state that is used while lowering AST types to CIR types.
Definition CIRGenTypes.h:51
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 & arrangeCIRFunctionInfo(CanQualType returnType, bool isInstanceMethod, llvm::ArrayRef< CanQualType > argTypes, FunctionType::ExtInfo info, RequiredArgs required)
const CIRGenFunctionInfo & arrangeFreeFunctionCall(const CallArgList &args, const FunctionType *fnType)
const CIRGenFunctionInfo & arrangeFreeFunctionType(CanQual< FunctionProtoType > fpt)
const CIRGenFunctionInfo & arrangeBuiltinFunctionCall(QualType resultType, const CallArgList &args)
A builtin function is a freestanding function using the default C conventions.
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...
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
bool inheritingCtorHasParams(const InheritedConstructor &inherited, CXXCtorType type)
Determine if a C++ inheriting constructor should have parameters matching those of its inherited cons...
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.
mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)
Convert type T into an mlir::Type.
void addUncopiedAggregate(LValue lvalue, clang::QualType type)
Definition CIRGenCall.h:241
void add(RValue rvalue, clang::QualType type)
Definition CIRGenCall.h:239
Address getAddress() const
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:260
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:2637
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
bool isImplicitObjectMemberFunction() const
[C++2b][dcl.fct]/p7 An implicit object member function is a non-static member function without an exp...
Definition DeclCXX.cpp:2726
bool isVirtual() const
Definition DeclCXX.h:2200
Qualifiers getMethodQualifiers() const
Definition DeclCXX.h:2323
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:2954
SourceLocation getBeginLoc() const
Definition Expr.h:3288
ConstExprIterator const_arg_iterator
Definition Expr.h:3202
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.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
llvm::DenormalMode FPDenormalMode
The floating-point denormal mode to use.
llvm::DenormalMode FP32DenormalMode
The floating-point denormal mode to use, for float.
std::string TrapFuncName
If not an empty string, trap intrinsics are lowered to calls to this function instead of to trap inst...
std::vector< std::string > DefaultFunctionAttrs
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3355
bool constructsVirtualBase() const
Returns true if the constructed base class is a virtual base class subobject of this declaration's cl...
Definition DeclCXX.h:3802
T * getAttr() const
Definition DeclBase.h:581
bool hasAttr() const
Definition DeclBase.h:585
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:454
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2058
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4612
Represents a K&R-style 'int foo()' function, which has no information available about its arguments.
Definition TypeBase.h:4999
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5421
ExceptionSpecificationType getExceptionSpecType() const
Get the kind of exception specification on this function.
Definition TypeBase.h:5728
bool isNothrow(bool ResultIfDependent=false) const
Determine whether this function type has a non-throwing exception specification.
Definition TypeBase.h:5820
A class which abstracts out some details necessary for making a call.
Definition TypeBase.h:4728
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4617
ExtInfo getExtInfo() const
Definition TypeBase.h:4973
QualType getReturnType() const
Definition TypeBase.h:4957
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
CXXCtorType getCtorType() const
Definition GlobalDecl.h:108
GlobalDecl getWithKernelReferenceKind(KernelReferenceKind Kind)
Definition GlobalDecl.h:203
const Decl * getDecl() const
Definition GlobalDecl.h:106
Description of a constructor that was inherited from a base class.
Definition DeclCXX.h:2608
ConstructorUsingShadowDecl * getShadowDecl() const
Definition DeclCXX.h:2620
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::vector< std::string > NoBuiltinFuncs
A list of all -fno-builtin-* function names (e.g., memset).
bool isNoBuiltinFunc(StringRef Name) const
Is this a libc/libm function that is no longer recognized as a builtin because a -fno-builtin-* optio...
SanitizerSet Sanitize
Set of enabled sanitizers.
bool assumeFunctionsAreConvergent() const
Represents a matrix type, as defined in the Matrix Types clang extensions.
Definition TypeBase.h:4451
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isTriviallyCopyableType(const ASTContext &Context) const
Return true if this is a trivially copyable type (C++0x [basic.types]p9)
Definition Type.cpp:2996
QualType getCanonicalType() const
Definition TypeBase.h:8556
LangAS getAddressSpace() const
Definition TypeBase.h:572
bool isParamDestroyedInCallee() const
Definition Decl.h:4609
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:343
bool hasConstructorVariants() const
Does this ABI have different entrypoints for complete-object and base-subobject constructors?
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
bool isVoidType() const
Definition TypeBase.h:9113
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isVoidPointerType() const
Definition Type.cpp:749
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
Definition Type.cpp:2547
CanQualType getCanonicalTypeUnqualified() const
bool isReferenceType() const
Definition TypeBase.h:8765
bool isScalarType() const
Definition TypeBase.h:9219
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isBitIntType() const
Definition TypeBase.h:9016
RecordDecl * castAsRecordDecl() const
Definition Type.h:48
bool isMemberPointerType() const
Definition TypeBase.h:8822
bool isObjectType() const
Determine whether this type is an object type.
Definition TypeBase.h:2574
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition Type.cpp:2557
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2427
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2998
bool isAnyPointerType() const
Definition TypeBase.h:8749
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9340
bool isNullPtrType() const
Definition TypeBase.h:9150
bool isRecordType() const
Definition TypeBase.h:8868
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:932
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2171
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2822
Represents a GCC generic vector type.
Definition TypeBase.h:4289
bool isSized(mlir::Type ty)
Returns true if the type is a CIR sized type.
Definition CIRTypes.cpp:35
@ 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.
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
Definition Utils.h:56
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
CXXCtorType
C++ constructor types.
Definition ABI.h:24
@ Ctor_Complete
Complete object ctor.
Definition ABI.h:25
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ CPlusPlus
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:152
@ Vector
'vector' clause, allowed on 'loop', Combined, and 'routine' directives.
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
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 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
RValue getRValue(CIRGenFunction &cgf, mlir::Location loc) const
void copyInto(CIRGenFunction &cgf, Address addr, mlir::Location loc) const
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.
Definition Sanitizers.h:174