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
commonBuildCXXMemberOrOperatorCall(CIRGenFunction & cgf,const CXXMethodDecl * md,mlir::Value thisPtr,mlir::Value implicitParam,QualType implicitParamTy,const CallExpr * ce,CallArgList & args,CallArgList * rtlArgs)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
emitCXXMemberOrOperatorMemberCallExpr(const CallExpr * ce,const CXXMethodDecl * md,ReturnValueSlot returnValue,bool hasQualifier,NestedNameSpecifier * qualifier,bool isArrow,const Expr * base)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
emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr * e,const CXXMethodDecl * md,ReturnValueSlot returnValue)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
emitCXXMemberOrOperatorCall(const CXXMethodDecl * md,const CIRGenCallee & callee,ReturnValueSlot returnValue,mlir::Value thisPtr,mlir::Value implicitParam,QualType implicitParamTy,const CallExpr * ce,CallArgList * rtlArgs)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
emitCXXNewAllocSize(CIRGenFunction & cgf,const CXXNewExpr * e,unsigned minElements,mlir::Value & numElements,mlir::Value & sizeWithoutCookie)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
storeAnyExprIntoOneUnit(CIRGenFunction & cgf,const Expr * init,QualType allocType,Address newPtr,AggValueSlot::Overlap_t mayOverlap)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
emitNewInitializer(CIRGenFunction & cgf,const CXXNewExpr * e,QualType elementType,mlir::Type elementTy,Address newPtr,mlir::Value numElements,mlir::Value allocSizeWithoutCookie)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.
emitNewDeleteCall(CIRGenFunction & cgf,const FunctionDecl * calleeDecl,const FunctionProtoType * calleeType,const CallArgList & args)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
emitCXXNewExpr(const CXXNewExpr * e)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