Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp
213799 views
1
//===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===//
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
// This contains code dealing with code generation of C++ expressions
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "CIRGenCXXABI.h"
14
#include "CIRGenFunction.h"
15
16
#include "clang/AST/DeclCXX.h"
17
#include "clang/AST/ExprCXX.h"
18
#include "clang/CIR/MissingFeatures.h"
19
20
using namespace clang;
21
using namespace clang::CIRGen;
22
23
namespace {
24
struct MemberCallInfo {
25
RequiredArgs reqArgs;
26
// Number of prefix arguments for the call. Ignores the `this` pointer.
27
unsigned prefixSize;
28
};
29
} // namespace
30
31
static MemberCallInfo commonBuildCXXMemberOrOperatorCall(
32
CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr,
33
mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce,
34
CallArgList &args, CallArgList *rtlArgs) {
35
assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) ||
36
isa<CXXOperatorCallExpr>(ce));
37
assert(md->isInstance() &&
38
"Trying to emit a member or operator call expr on a static method!");
39
40
// Push the this ptr.
41
const CXXRecordDecl *rd =
42
cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md);
43
args.add(RValue::get(thisPtr), cgf.getTypes().deriveThisType(rd, md));
44
45
// If there is an implicit parameter (e.g. VTT), emit it.
46
if (implicitParam) {
47
args.add(RValue::get(implicitParam), implicitParamTy);
48
}
49
50
const auto *fpt = md->getType()->castAs<FunctionProtoType>();
51
RequiredArgs required =
52
RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size());
53
unsigned prefixSize = args.size() - 1;
54
55
// Add the rest of the call args
56
if (rtlArgs) {
57
// Special case: if the caller emitted the arguments right-to-left already
58
// (prior to emitting the *this argument), we're done. This happens for
59
// assignment operators.
60
args.addFrom(*rtlArgs);
61
} else if (ce) {
62
// Special case: skip first argument of CXXOperatorCall (it is "this").
63
unsigned argsToSkip = isa<CXXOperatorCallExpr>(ce) ? 1 : 0;
64
cgf.emitCallArgs(args, fpt, drop_begin(ce->arguments(), argsToSkip),
65
ce->getDirectCallee());
66
} else {
67
assert(
68
fpt->getNumParams() == 0 &&
69
"No CallExpr specified for function with non-zero number of arguments");
70
}
71
72
// return {required, prefixSize};
73
return {required, prefixSize};
74
}
75
76
RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(
77
const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue,
78
bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow,
79
const Expr *base) {
80
assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce));
81
82
if (md->isVirtual()) {
83
cgm.errorNYI(ce->getSourceRange(),
84
"emitCXXMemberOrOperatorMemberCallExpr: virtual call");
85
return RValue::get(nullptr);
86
}
87
88
// Note on trivial assignment
89
// --------------------------
90
// Classic codegen avoids generating the trivial copy/move assignment operator
91
// when it isn't necessary, choosing instead to just produce IR with an
92
// equivalent effect. We have chosen not to do that in CIR, instead emitting
93
// trivial copy/move assignment operators and allowing later transformations
94
// to optimize them away if appropriate.
95
96
// C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
97
// operator before the LHS.
98
CallArgList rtlArgStorage;
99
CallArgList *rtlArgs = nullptr;
100
if (auto *oce = dyn_cast<CXXOperatorCallExpr>(ce)) {
101
if (oce->isAssignmentOp()) {
102
rtlArgs = &rtlArgStorage;
103
emitCallArgs(*rtlArgs, md->getType()->castAs<FunctionProtoType>(),
104
drop_begin(ce->arguments(), 1), ce->getDirectCallee(),
105
/*ParamsToSkip*/ 0);
106
}
107
}
108
109
LValue thisPtr;
110
if (isArrow) {
111
LValueBaseInfo baseInfo;
112
assert(!cir::MissingFeatures::opTBAA());
113
Address thisValue = emitPointerWithAlignment(base, &baseInfo);
114
thisPtr = makeAddrLValue(thisValue, base->getType(), baseInfo);
115
} else {
116
thisPtr = emitLValue(base);
117
}
118
119
if (isa<CXXConstructorDecl>(md)) {
120
cgm.errorNYI(ce->getSourceRange(),
121
"emitCXXMemberOrOperatorMemberCallExpr: constructor call");
122
return RValue::get(nullptr);
123
}
124
125
if ((md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion())) &&
126
isa<CXXDestructorDecl>(md))
127
return RValue::get(nullptr);
128
129
// Compute the function type we're calling
130
const CXXMethodDecl *calleeDecl = md;
131
const CIRGenFunctionInfo *fInfo = nullptr;
132
if (isa<CXXDestructorDecl>(calleeDecl)) {
133
cgm.errorNYI(ce->getSourceRange(),
134
"emitCXXMemberOrOperatorMemberCallExpr: destructor call");
135
return RValue::get(nullptr);
136
}
137
138
fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl);
139
140
mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);
141
142
assert(!cir::MissingFeatures::sanitizers());
143
assert(!cir::MissingFeatures::emitTypeCheck());
144
145
if (isa<CXXDestructorDecl>(calleeDecl)) {
146
cgm.errorNYI(ce->getSourceRange(),
147
"emitCXXMemberOrOperatorMemberCallExpr: destructor call");
148
return RValue::get(nullptr);
149
}
150
151
assert(!cir::MissingFeatures::sanitizers());
152
if (getLangOpts().AppleKext) {
153
cgm.errorNYI(ce->getSourceRange(),
154
"emitCXXMemberOrOperatorMemberCallExpr: AppleKext");
155
return RValue::get(nullptr);
156
}
157
CIRGenCallee callee =
158
CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));
159
160
return emitCXXMemberOrOperatorCall(
161
calleeDecl, callee, returnValue, thisPtr.getPointer(),
162
/*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);
163
}
164
165
RValue
166
CIRGenFunction::emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,
167
const CXXMethodDecl *md,
168
ReturnValueSlot returnValue) {
169
assert(md->isInstance() &&
170
"Trying to emit a member call expr on a static method!");
171
return emitCXXMemberOrOperatorMemberCallExpr(
172
e, md, returnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr,
173
/*IsArrow=*/false, e->getArg(0));
174
}
175
176
RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
177
const CXXMethodDecl *md, const CIRGenCallee &callee,
178
ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,
179
QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {
180
const auto *fpt = md->getType()->castAs<FunctionProtoType>();
181
CallArgList args;
182
MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(
183
*this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);
184
auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(
185
args, fpt, callInfo.reqArgs, callInfo.prefixSize);
186
assert((ce || currSrcLoc) && "expected source location");
187
mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;
188
assert(!cir::MissingFeatures::opCallMustTail());
189
return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
190
}
191
192
static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
193
unsigned minElements,
194
mlir::Value &numElements,
195
mlir::Value &sizeWithoutCookie) {
196
QualType type = e->getAllocatedType();
197
mlir::Location loc = cgf.getLoc(e->getSourceRange());
198
199
if (!e->isArray()) {
200
CharUnits typeSize = cgf.getContext().getTypeSizeInChars(type);
201
sizeWithoutCookie = cgf.getBuilder().getConstant(
202
loc, cir::IntAttr::get(cgf.SizeTy, typeSize.getQuantity()));
203
return sizeWithoutCookie;
204
}
205
206
cgf.cgm.errorNYI(e->getSourceRange(), "emitCXXNewAllocSize: array");
207
return {};
208
}
209
210
static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
211
QualType allocType, Address newPtr,
212
AggValueSlot::Overlap_t mayOverlap) {
213
// FIXME: Refactor with emitExprAsInit.
214
switch (cgf.getEvaluationKind(allocType)) {
215
case cir::TEK_Scalar:
216
cgf.emitScalarInit(init, cgf.getLoc(init->getSourceRange()),
217
cgf.makeAddrLValue(newPtr, allocType), false);
218
return;
219
case cir::TEK_Complex:
220
cgf.cgm.errorNYI(init->getSourceRange(),
221
"storeAnyExprIntoOneUnit: complex");
222
return;
223
case cir::TEK_Aggregate: {
224
assert(!cir::MissingFeatures::aggValueSlotGC());
225
assert(!cir::MissingFeatures::sanitizers());
226
AggValueSlot slot = AggValueSlot::forAddr(
227
newPtr, allocType.getQualifiers(), AggValueSlot::IsDestructed,
228
AggValueSlot::IsNotAliased, mayOverlap, AggValueSlot::IsNotZeroed);
229
cgf.emitAggExpr(init, slot);
230
return;
231
}
232
}
233
llvm_unreachable("bad evaluation kind");
234
}
235
236
static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,
237
QualType elementType, mlir::Type elementTy,
238
Address newPtr, mlir::Value numElements,
239
mlir::Value allocSizeWithoutCookie) {
240
assert(!cir::MissingFeatures::generateDebugInfo());
241
if (e->isArray()) {
242
cgf.cgm.errorNYI(e->getSourceRange(), "emitNewInitializer: array");
243
} else if (const Expr *init = e->getInitializer()) {
244
storeAnyExprIntoOneUnit(cgf, init, e->getAllocatedType(), newPtr,
245
AggValueSlot::DoesNotOverlap);
246
}
247
}
248
249
/// Emit a call to an operator new or operator delete function, as implicitly
250
/// created by new-expressions and delete-expressions.
251
static RValue emitNewDeleteCall(CIRGenFunction &cgf,
252
const FunctionDecl *calleeDecl,
253
const FunctionProtoType *calleeType,
254
const CallArgList &args) {
255
cir::CIRCallOpInterface callOrTryCall;
256
cir::FuncOp calleePtr = cgf.cgm.getAddrOfFunction(calleeDecl);
257
CIRGenCallee callee =
258
CIRGenCallee::forDirect(calleePtr, GlobalDecl(calleeDecl));
259
RValue rv =
260
cgf.emitCall(cgf.cgm.getTypes().arrangeFreeFunctionCall(args, calleeType),
261
callee, ReturnValueSlot(), args, &callOrTryCall);
262
263
/// C++1y [expr.new]p10:
264
/// [In a new-expression,] an implementation is allowed to omit a call
265
/// to a replaceable global allocation function.
266
///
267
/// We model such elidable calls with the 'builtin' attribute.
268
assert(!cir::MissingFeatures::attributeBuiltin());
269
return rv;
270
}
271
272
mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
273
// The element type being allocated.
274
QualType allocType = getContext().getBaseElementType(e->getAllocatedType());
275
276
// 1. Build a call to the allocation function.
277
FunctionDecl *allocator = e->getOperatorNew();
278
279
// If there is a brace-initializer, cannot allocate fewer elements than inits.
280
unsigned minElements = 0;
281
if (e->isArray() && e->hasInitializer()) {
282
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array initializer");
283
}
284
285
mlir::Value numElements = nullptr;
286
mlir::Value allocSizeWithoutCookie = nullptr;
287
mlir::Value allocSize = emitCXXNewAllocSize(
288
*this, e, minElements, numElements, allocSizeWithoutCookie);
289
CharUnits allocAlign = getContext().getTypeAlignInChars(allocType);
290
291
// Emit the allocation call.
292
Address allocation = Address::invalid();
293
CallArgList allocatorArgs;
294
if (allocator->isReservedGlobalPlacementOperator()) {
295
cgm.errorNYI(e->getSourceRange(),
296
"emitCXXNewExpr: reserved global placement operator");
297
} else {
298
const FunctionProtoType *allocatorType =
299
allocator->getType()->castAs<FunctionProtoType>();
300
unsigned paramsToSkip = 0;
301
302
// The allocation size is the first argument.
303
QualType sizeType = getContext().getSizeType();
304
allocatorArgs.add(RValue::get(allocSize), sizeType);
305
++paramsToSkip;
306
307
if (allocSize != allocSizeWithoutCookie) {
308
CharUnits cookieAlign = getSizeAlign(); // FIXME: Ask the ABI.
309
allocAlign = std::max(allocAlign, cookieAlign);
310
}
311
312
// The allocation alignment may be passed as the second argument.
313
if (e->passAlignment()) {
314
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: pass alignment");
315
}
316
317
// FIXME: Why do we not pass a CalleeDecl here?
318
emitCallArgs(allocatorArgs, allocatorType, e->placement_arguments(),
319
AbstractCallee(), paramsToSkip);
320
RValue rv =
321
emitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
322
323
// Set !heapallocsite metadata on the call to operator new.
324
assert(!cir::MissingFeatures::generateDebugInfo());
325
326
// If this was a call to a global replaceable allocation function that does
327
// not take an alignment argument, the allocator is known to produce storage
328
// that's suitably aligned for any object that fits, up to a known
329
// threshold. Otherwise assume it's suitably aligned for the allocated type.
330
CharUnits allocationAlign = allocAlign;
331
if (!e->passAlignment() &&
332
allocator->isReplaceableGlobalAllocationFunction()) {
333
const TargetInfo &target = cgm.getASTContext().getTargetInfo();
334
unsigned allocatorAlign = llvm::bit_floor(std::min<uint64_t>(
335
target.getNewAlign(), getContext().getTypeSize(allocType)));
336
allocationAlign = std::max(
337
allocationAlign, getContext().toCharUnitsFromBits(allocatorAlign));
338
}
339
340
mlir::Value allocPtr = rv.getValue();
341
allocation = Address(
342
allocPtr, mlir::cast<cir::PointerType>(allocPtr.getType()).getPointee(),
343
allocationAlign);
344
}
345
346
// Emit a null check on the allocation result if the allocation
347
// function is allowed to return null (because it has a non-throwing
348
// exception spec or is the reserved placement new) and we have an
349
// interesting initializer will be running sanitizers on the initialization.
350
bool nullCheck = e->shouldNullCheckAllocation() &&
351
(!allocType.isPODType(getContext()) || e->hasInitializer());
352
assert(!cir::MissingFeatures::exprNewNullCheck());
353
if (nullCheck)
354
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: null check");
355
356
// If there's an operator delete, enter a cleanup to call it if an
357
// exception is thrown.
358
if (e->getOperatorDelete() &&
359
!e->getOperatorDelete()->isReservedGlobalPlacementOperator())
360
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
361
362
if (allocSize != allocSizeWithoutCookie)
363
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");
364
365
mlir::Type elementTy = convertTypeForMem(allocType);
366
Address result = builder.createElementBitCast(getLoc(e->getSourceRange()),
367
allocation, elementTy);
368
369
// Passing pointer through launder.invariant.group to avoid propagation of
370
// vptrs information which may be included in previous type.
371
// To not break LTO with different optimizations levels, we do it regardless
372
// of optimization level.
373
if (cgm.getCodeGenOpts().StrictVTablePointers &&
374
allocator->isReservedGlobalPlacementOperator())
375
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: strict vtable pointers");
376
377
assert(!cir::MissingFeatures::sanitizers());
378
379
emitNewInitializer(*this, e, allocType, elementTy, result, numElements,
380
allocSizeWithoutCookie);
381
return result.getPointer();
382
}
383
384